注意: 本文是从日语原文机器翻译而来的。如果您发现翻译错误,请告知我们。
在开设LOPPO画材涩谷店(无人销售所)时,用2天时间构建的无现金·完全自助收银系统的解说。
开始:LOPPO画材的无人销售所项目
LOPPO画材是从高桥的兴趣爱好开始的赛璐珞画用品品牌,至今主要以网上销售为中心进行展开。 今年年初,作为LOPPO画材的活动空间租借了小型商铺,原本计划将其一角作为商品库存存放处,但突然想到"既然要存放库存,是否可以直接作为销售所"的想法。
实体店铺的需求之前就有,但确保店铺运营所需的人力资源很困难。 于是想到的就是"画材无人销售所"这种形态。像蔬菜无人销售所一样,24小时365天都能买到赛璐珞画用品的梦想般(疯狂的!)场所。
画材无人销售所(示意图)
1. 现有自助收银的问题与解决方案
要实现不需要常驻员工的无人销售所,需要完全自助的收银系统。这次以防盗对策为前提,只对应无现金支付。
最初考虑了市售的自助收银解决方案,但有两个大问题。
- 除了初期费用外,月固定费用很高
- 到账周期长
要提高可持续性,重要的是将固定费用抑制到最小限度,同时保持良好的现金流。 因此注意到了过去参展活动时导入的Square支付系统。
Square不仅对应多样的支付手段,月固定费用为零(仅支付手续费),最快次个工作日到账的迅速到账周期很有魅力。 另外通过Square API可以制作定制应用程序。 由于已经拥有Square Terminal,通过利用这个判断可以抑制初期费用。
但是,在开发方面有很大的限制。仅店铺开业的商品制造业务就忙不过来,自助收银系统的开发只能分配仅仅2天的时间。
2. 系统设计:安全易用的自助收银
整体架构
系统主要由以下组件构成。
- Linux应用服务器:React前端和Express后端
- 店内系统:Windows 11 Pro信息终端模式的客户端终端、周边设备、Square Terminal
- Square服务:Square API、商品主数据
- 监控·运维系统:监控摄像头、不间断电源装置、网络冗余化
用户看到的只有触摸对应显示器、条码扫描器以及Square Terminal。客户端在Windows 11 Pro的信息终端模式下运行,主要应用程序逻辑在店外的Linux机器上。
安全与网络
网络在使用Tailscale的VPN环境下,由此保护客户端终端与Linux服务器间的通信。 另外,所有设备的电源连接到不间断电源装置进行雷击·停电对策,网络也进行了冗余化确保稳定运行。
通过导入Tailscale,远程维护也变得容易。 各终端完全不保存本地数据,全部从Square数据获取的机制。
硬件构成
- 触摸对应显示器
- USB条码扫描器
- Square Terminal(支付处理·收据打印)
- 监控摄像头(实时监控用)
前端实现
支付手段选择画面
前端用React实现,由以下主要画面构成。
- 商品扫描画面
- 支付手段选择画面
- 支付处理中画面
- 支付完成画面
虽然是机器翻译但也进行了多语言化,对应日语、英语、法语、西班牙语、繁体中文、简体中文的6种语言。 由此,访日外国游客也能安心使用。
// 语言设定的例子
const translations = {
ja: {
title: 'セルフレジシステム',
scanTitle: '商品スキャン',
// ...省略
},
en: {
title: 'Self-Checkout System',
scanTitle: 'Product Scan',
// ...省略
},
// 其他语言...
};
另外,设计为优先接收条码扫描器的输入,致力于用户不会迷惑的界面。
3. Square API活用要点
通过Terminal API进行支付处理
Square API中特别重要的是Terminal API。通过使用这个,可以向Square Terminal请求支付处理。
// Terminal 结账生成
app.post("/api/create-terminal-checkout", async (req, res) => {
try {
const { order, amountMoney, paymentType = "CARD_PRESENT" } = req.body;
const ALLOWED = new Set([
"CARD_PRESENT",
"FELICA_TRANSPORTATION_GROUP",
"FELICA_ID",
"FELICA_QUICPAY",
"QR_CODE"
]);
if (!ALLOWED.has(paymentType)) {
return res.status(400).json({ error: "指定了不支持的支付手段" });
}
// 先创建订单
const orderId = await createOrder(order);
// 创建Square Terminal Checkout
const checkoutResponse = await squareClient.terminal.checkouts.create({
idempotencyKey: randomUUID(),
checkout: {
amountMoney: {
// 金额必须是 BigInt
amount: BigInt(amountMoney.amount),
currency: amountMoney.currency,
},
deviceOptions: {
deviceId: SQUARE_DEVICE_ID,
skip_receipt_screen: true,
show_itemized_cart: false,
},
referenceId: orderId,
orderId,
note: "LOPPO自助收银的支付",
paymentType: paymentType
},
});
res.json(checkoutResponse);
} catch (error) {
handleError("Terminal Checkout 创建错误", error, res);
}
});
多样的支付手段
由于Square Terminal对应多样的支付手段,客户可以用自己喜欢的方法进行支付。
- 信用卡·借记卡
- 交通系IC(Suica/PASMO等)
- iD
- QUICPay
- QR码支付(PayPay等)
不过不对应银联卡。
支付状况确认的轮询
由于支付处理在Square Terminal上进行,需要通过轮询确认支付完成或取消等状态。
// 通过轮询确认支付状况
const checkPaymentStatus = async () => {
try {
const statusResponse = await fetch(`/api/get-checkout-status?checkoutId=${data.checkout.id}`);
const statusData = await statusResponse.json();
if (statusData.status === 'COMPLETED') {
setPaymentStatus(t.paymentCompleted);
// 完成处理
setTimeout(() => {
setStatus('complete');
setCart([]);
}, 2000);
} else if (statusData.status === 'CANCELED' || statusData.status === 'CANCEL_REQUESTED') {
setPaymentStatus(t.paymentCanceled);
setTimeout(() => {
setStatus('ready');
}, 3000);
} else {
// 还未完成的情况下再次确认
setPaymentStatus(t.processing);
setTimeout(checkPaymentStatus, 2000);
}
} catch (error) {
console.error(t.statusCheckFailed, error);
setPaymentStatus(t.statusCheckFailed);
setTimeout(() => {
setStatus('ready');
}, 3000);
}
};
商品主数据管理
商品信息全部在Square的管理画面进行登录,通过API获取。 由此简化了商品追加和价格变更等运营作业。
app.get("/api/catalog-items", async (_req, res) => {
try {
const TYPES = "ITEM,ITEM_VARIATION,CATEGORY,IMAGE"; // 列举所有必要的类型
//------------------------------------------------------------------
// ① 全部读取
//------------------------------------------------------------------
const objects = [];
for await (const obj of await squareClient.catalog.list({ types: TYPES }))
objects.push(obj);
//------------------------------------------------------------------
// ② 先将 CATEGORY / IMAGE / VARIATION 制作成地图
//------------------------------------------------------------------
const imageMap = {};
const categoryMap = {};
const variationMap = {};
// ...省略(地图制作处理)
//------------------------------------------------------------------
// ③ 展开 ITEM,用先制作的地图嵌入信息
//------------------------------------------------------------------
const filtered = objects
.filter((o) => o.type === "ITEM")
.map((item) => {
// ...省略(数据变换处理)
})
// -- 这里是要求过滤器 --
.filter(
(item) =>
!item.isArchived &&
item.categoryNames.includes("LOPPO画材")
);
res.json(filtered);
} catch (error) {
handleError("目录项目获取错误", error, res);
}
});
4. 通过LLM活用实现超速开发
这个项目的最大特征是在仅仅2天这样的短期间内完成了开发。 使这成为可能的是LLM(大规模语言模型)的活用。
开发时间的内容分配
- 基本系统开发:约2小时
- 改良·UI调整:约4小时
- 测试·部署:剩余时间
Claude 3.7 Sonnet的活用方法
开发中主要活用了Claude 3.7 Sonnet,提高了实现效率。 不仅应用程序逻辑,UI设计也轻松处理,甚至准备了设置文档等,可谓至贴至心。 特别是多语言对应的代码和与Square API的联动部分,LLM的提案非常有用。
另外ChatGPT 4o和ChatGPT o3等也组合使用了,但在对WEB应用程序的理解度方面完全不及3.7 Sonnet。
LLM活用的具体例子
在开发中活用LLM时的理所当然的注意点是,很难直接使用生成的代码,必须在理解之上进行必要的修正。 例如,在与Square Terminal API的联动部分需要以下修正。
- 支付手段的追加:LLM生成的代码只对应信用卡支付,需要追加选择支付手段的画面
- 错误处理:Terminal的支付取消事件的处理方法有误,基于API文档修正为正确的处理
- 安全性:一部分用脆弱协议进行应用程序间通信,构建了私有VPN确保通信路径的安全性
LLM提供了基本的代码结构,但为了能够承受实际运营需要手工进行调整。
5. 国际化与易用性
多语言对应的实现
为了访日外国人也能使用,系统对应日语、英语、法语、西班牙语、繁体中文、简体中文的6种语言。 在React组件内管理语言设定,采用了从翻译对象获取画面上所有文本的方式。
// 语言选择的状态管理
const [language, setLanguage] = useState('ja'); // 将默认语言设定为日语
// 获取语言设定
const t = translations[language];
// 使用例子
<h1 className="text-4xl font-bold">{t.title}</h1>
<p className="text-lg text-gray-700 mb-6">
{t.scanDescription}
</p>
易用性的设计
以与超市和便利店的自助收银同等的易用性为目标,进行了以下设计。
- 条码扫描优先:在页面任意地方接收键盘输入,常时优先条码扫描器的输入
- 大按钮:容易触摸操作的大按钮尺寸
- 明确的反馈:容易理解操作结果的消息显示
通过这些设计,实现了用户不会迷惑就能操作的界面。
6. 运营面的设计
实时监控与故障对应
在店内设置网络摄像头,能够实时确认销售所的状况。 发生问题时,客户联系店头贴示的电话号码就能够对应。
检测到运营上的异常时,整备了30分钟~2小时内赶到现地进行对应的体制。 另外,万一支付终端不运行的情况下,也准备了事后传递支付链接完成支付的替代手段。
为了稳定运行,也组合了通过不间断电源装置的电源备份、网络的冗余化、无操作时的定期重启等。
只有1次发生了客户端电源线插入不牢固而脱落的问题,但此后系统非常稳定。
7. 实际成果与效果
销售机会的扩大
通过开设无人销售所,获得了都心站近24小时营业这样珍贵的销售机会。 在应对实体店铺开设要求的同时,克服了人力资源制约是最大的成果。
支付方法的倾向
导入的所有支付方法都均匀地被利用,但特别受欢迎的依次是以下顺序。
- 交通系IC
- QR码支付(PayPay等)
- 信用卡(触摸支付)
8. 今后的展望与扩张计划
向网上销售的展开
现在的LOPPO画材EC网站是用BASE构建的,但预定变更为用Square API的。 由此不仅能够节约支付手续费,还能改善商品的购买流程,另外还有店铺和网上销售的库存·销售管理一元化的优点。
进一步地,还想提供网上购买店头取货的手段。
总结:能制作颜料的话收银系统也能制作
LOPPO以手工复刻了各种赛璐珞画相关画材,这次手工制作了收银系统。
软件应用程序像这样通过活用既有API和LLM的支援,有时能够比较简单地构建。 话虽如此,没想到收银系统能这么简单地制作,学到了很多。
重点关注的点
- 既有服务的活用:最大限度活用Square API等既有平台
- LLM等支援工具的活用:积极导入提高开发效率的工具
- 集中在必要最小限的范围:限定在必要功能进行简单实现
希望能成为对自助收银系统构建有兴趣的人或者考虑活用Square API的人的参考。
