当我在 commercetools API 上从购物车创建订单时(记录在此: http: //dev.commercetools.com/http-api-projects-orders.html#create-order-from-cart),我必须设置orderNumber 手动。数字很重要,因为商务工具平台的内部 ID 是长 UUID,在履行和支付过程中不实用。
可靠地生成顺序递增且唯一的订单号的最佳方法是什么(在这种情况下没有外部系统生成它们,不必为这种情况引入一个会很好)?
当我在 commercetools API 上从购物车创建订单时(记录在此: http: //dev.commercetools.com/http-api-projects-orders.html#create-order-from-cart),我必须设置orderNumber 手动。数字很重要,因为商务工具平台的内部 ID 是长 UUID,在履行和支付过程中不实用。
可靠地生成顺序递增且唯一的订单号的最佳方法是什么(在这种情况下没有外部系统生成它们,不必为这种情况引入一个会很好)?
执行此操作的一个好方法是使用自定义对象来包含您的顺序订单号。在创建订单时,您可以尝试更新此自定义对象http://dev.commercetools.com/http-api-projects-custom-objects.html#create-or-update-a-customobject。如果更新成功,您可以使用该数字作为 orderNumber,如果失败,增加并重试。
回顾一下:当您要将购物车变成订单时,请从您的自定义对象中获取当前订单号。然后,尝试增加它。如果成功,则使用该编号作为订单的 orderNumber。
正如@svaj 所说,您可以使用自定义对象获取客户或订单的序列号。由于版本,自定义对象将充当锁,避免两个并发请求可能获得相同的数字。如果出现并发错误,您还可以使用递归重试。
这是 ES6 中的一个工作示例(同样适用于订单号)。您唯一需要设置的是序列的名称,它将成为自定义对象的容器和键(例如“ customerSequence ”)。
setCustomerNumber({ sequence, value, version }) {
return customObjectsService
.save({
container: sequence,
key: sequence,
value,
version,
})
.then(customObject => customObject.value);
},
getCustomerNumber(sequence) {
return customObjectsService
.find({ where: `key="${sequence}"` })
.then(({ results }) => (results.length ? results[0] : { value: 0 }))
.then(lastValue => {
return this.setCustomerNumber({
sequence,
value: lastValue.value + 1,
version: lastValue.version,
}).catch(() => this.getCustomerNumber(sequence)); // We request a new one on error
});
},
在这里你有前面代码的单元测试
describe('when getting the next customer number', () => {
const sequence = 'customersSequence';
describe('when existing previous customer number', () => {
const oldCustomerNumber = 1;
const newCustomerNumber = oldCustomerNumber + 1;
const version = 1;
beforeEach(() => {
spyOn(customObjectsService, 'find').and.returnValue(
Promise.resolve({
results: [
{
value: oldCustomerNumber,
version,
},
],
total: 1,
}),
);
spyOn(customersService, 'setCustomerNumber').and.returnValue(
Promise.resolve(newCustomerNumber),
);
});
it('should get a customer number equals to <previous customer number> + 1', done => {
customersService
.getCustomerNumber(sequence)
.then(customerNumber => {
expect(customObjectsService.find).toHaveBeenCalledWith({
where: `key="${sequence}"`,
});
expect(customersService.setCustomerNumber).toHaveBeenCalledWith({
sequence,
value: newCustomerNumber,
version,
});
expect(customerNumber).toBe(newCustomerNumber);
})
.then(done, done.fail);
});
});
describe('when NOT existing previous customer number', () => {
const newCustomerNumber = 1;
beforeEach(() => {
spyOn(customObjectsService, 'find').and.returnValue(
Promise.resolve({
results: [],
total: 0,
}),
);
spyOn(customersService, 'setCustomerNumber').and.returnValue(
Promise.resolve(newCustomerNumber),
);
});
it('should get a customer number equals to 1', done => {
customersService
.getCustomerNumber(sequence)
.then(customerNumber => {
expect(customObjectsService.find).toHaveBeenCalledWith({
where: `key="${sequence}"`,
});
expect(customersService.setCustomerNumber).toHaveBeenCalledWith({
sequence,
value: newCustomerNumber,
version: undefined,
});
expect(customerNumber).toBe(newCustomerNumber);
})
.then(done, done.fail);
});
});
});
如果您使用 Java 编写集成(使用 CommerceTools Java SDK),那么您可以使用 java.util.concurrent.atomic.AtomicLong。这是一个在 CommerceTools 中创建订单后将订单号设置为订单的示例。
首先像这样在你的类中定义一个静态变量
private static final AtomicLong sequence = new AtomicLong(System.currentTimeMillis() / 1000);
然后可以在这样的方法中使用它
public void setOrderNumber(Order order) throws ShoppingCartException {
long orderNumber = sequence.incrementAndGet();
// command to set order number
SetOrderNumber action = SetOrderNumber.of(String.valueOf(orderNumber));
OrderUpdateCommand command = OrderUpdateCommand.of(order, action);
// execute the command
try {
// some code to get a Java SDK client
BlockingSphereClient client = ...;
this.order = client.executeBlocking(command);
} catch (Exception e) {
// log/throw exeception
}
}