@tallyui/connector-woocommerce 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +10 -2
- package/dist/index.js +49 -24
- package/package.json +3 -3
- package/src/commands/transport.ts +46 -23
- package/src/store-settings.ts +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { SyncContext, ServerCapabilities, StoreSettings, Customer, CustomerInput
|
|
|
2
2
|
export { ConnectorUnauthorizedError } from '@tallyui/core';
|
|
3
3
|
import { RxJsonSchema } from 'rxdb';
|
|
4
4
|
|
|
5
|
-
/** The highest order.create version the WooCommerce transport maps: discounts and
|
|
6
|
-
declare const WOO_ORDER_CREATE_VERSION =
|
|
5
|
+
/** The highest order.create version the WooCommerce transport maps: v4's net discounts, and v5's fees, shipping and custom lines (WCPOS push/orders; orders #146, #161). */
|
|
6
|
+
declare const WOO_ORDER_CREATE_VERSION = 5;
|
|
7
7
|
declare function wooStoreSettings(context: SyncContext): Promise<StoreSettings>;
|
|
8
8
|
declare function readWooCapabilities(context: SyncContext): Promise<ServerCapabilities | undefined>;
|
|
9
9
|
|
|
@@ -62,6 +62,14 @@ interface WooLocalOrder {
|
|
|
62
62
|
id: string;
|
|
63
63
|
netMicros?: string;
|
|
64
64
|
}>;
|
|
65
|
+
fees?: ReadonlyArray<{
|
|
66
|
+
id: string;
|
|
67
|
+
netMicros?: string;
|
|
68
|
+
}>;
|
|
69
|
+
shipping?: ReadonlyArray<{
|
|
70
|
+
id: string;
|
|
71
|
+
netMicros?: string;
|
|
72
|
+
}>;
|
|
65
73
|
}
|
|
66
74
|
declare function toWooOrderPayload(envelope: OrderCreateEnvelope, local?: WooLocalOrder, options?: {
|
|
67
75
|
paymentsList?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -718,7 +718,7 @@ function createWooCustomers(options) {
|
|
|
718
718
|
|
|
719
719
|
// src/store-settings.ts
|
|
720
720
|
import { ConnectorUnauthorizedError as ConnectorUnauthorizedError2, StoreSettingsError, minorUnitDigits, woocommerceTax } from "@tallyui/core";
|
|
721
|
-
var WOO_ORDER_CREATE_VERSION =
|
|
721
|
+
var WOO_ORDER_CREATE_VERSION = 5;
|
|
722
722
|
async function wooStoreSettings(context) {
|
|
723
723
|
try {
|
|
724
724
|
const init = { method: "GET", headers: context.headers, signal: context.signal };
|
|
@@ -841,7 +841,7 @@ async function readWooCapabilities(context) {
|
|
|
841
841
|
}
|
|
842
842
|
|
|
843
843
|
// package.json
|
|
844
|
-
var version = "3.
|
|
844
|
+
var version = "3.4.0";
|
|
845
845
|
|
|
846
846
|
// src/commands/transport.ts
|
|
847
847
|
import { minorUnitDigits as minorUnitDigits2, moneyFromDecimalString, moneyFromMajor as moneyFromMajor2 } from "@tallyui/core";
|
|
@@ -857,9 +857,6 @@ function wooMinorFromDecimal(text, currency) {
|
|
|
857
857
|
}
|
|
858
858
|
function toWooOrderPayload(envelope, local, options) {
|
|
859
859
|
const p = envelope.payload;
|
|
860
|
-
if (envelope.version === 5 && (p.fees?.length || p.shipping?.length || p.lines.some((line) => line.custom))) {
|
|
861
|
-
return { error: { code: "invalid_payload", message: "Fees, shipping and custom lines are not supported by this connector yet." } };
|
|
862
|
-
}
|
|
863
860
|
if (p.payments.length === 0 || p.payments.length > 1 && !options?.paymentsList) {
|
|
864
861
|
return { error: { code: "invalid_payload", message: "WooCommerce orders take one payment." } };
|
|
865
862
|
}
|
|
@@ -870,35 +867,61 @@ function toWooOrderPayload(envelope, local, options) {
|
|
|
870
867
|
return { error: { code: "invalid_payload", message: "Payments do not add up to the order total." } };
|
|
871
868
|
}
|
|
872
869
|
for (const line of p.lines) {
|
|
873
|
-
if (!/^[1-9]\d*$/.test(line.variantId ?? "") || !Number.isSafeInteger(Number(line.variantId))) {
|
|
870
|
+
if (!line.custom && (!/^[1-9]\d*$/.test(line.variantId ?? "") || !Number.isSafeInteger(Number(line.variantId)))) {
|
|
874
871
|
return { error: { code: "invalid_payload", message: `Line ${line.clientLineId} has no WooCommerce product id.` } };
|
|
875
872
|
}
|
|
876
873
|
}
|
|
877
874
|
const digits = p.display?.exponent ?? minorUnitDigits2(p.currency);
|
|
878
875
|
const major = (minor) => (minor / 10 ** digits).toFixed(digits);
|
|
876
|
+
const inclusiveNet = (netMicros, id) => {
|
|
877
|
+
if (netMicros === void 0) {
|
|
878
|
+
return { error: { code: "unsupported_tax_mode", message: "Tax-inclusive prices need the till's WooCommerce tax figures; update the till." } };
|
|
879
|
+
}
|
|
880
|
+
const net = BigInt(netMicros), divisor = 10n ** BigInt(digits);
|
|
881
|
+
if (net < 0n) {
|
|
882
|
+
return { error: { code: "invalid_payload", message: `Line ${id} has a negative net.` } };
|
|
883
|
+
}
|
|
884
|
+
if (net % divisor !== 0n) {
|
|
885
|
+
return { error: { code: "invalid_payload", message: `Line ${id} has a net finer than 6 decimals.` } };
|
|
886
|
+
}
|
|
887
|
+
const micros = net / divisor;
|
|
888
|
+
return `${micros / 1000000n}.${(micros % 1000000n).toString().padStart(6, "0")}`;
|
|
889
|
+
};
|
|
879
890
|
const line_items = [];
|
|
880
891
|
for (const line of p.lines) {
|
|
881
|
-
let subtotal = major(line.unitPriceMinor * line.quantity);
|
|
882
892
|
let total = major(line.unitPriceMinor * line.quantity - (line.discountMinor ?? 0));
|
|
893
|
+
let subtotal = total;
|
|
883
894
|
if (line.taxInclusive ?? p.pricesIncludeTax) {
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
const netMicros = local?.lines.find((stored) => stored.id === line.clientLineId)?.netMicros;
|
|
888
|
-
if (netMicros === void 0) {
|
|
889
|
-
return { error: { code: "unsupported_tax_mode", message: "Tax-inclusive prices need the till's WooCommerce tax figures; update the till." } };
|
|
890
|
-
}
|
|
891
|
-
const net = BigInt(netMicros), divisor = 10n ** BigInt(digits);
|
|
892
|
-
if (net < 0n) {
|
|
893
|
-
return { error: { code: "invalid_payload", message: `Line ${line.clientLineId} has a negative net.` } };
|
|
894
|
-
}
|
|
895
|
-
if (net % divisor !== 0n) {
|
|
896
|
-
return { error: { code: "invalid_payload", message: `Line ${line.clientLineId} has a net finer than 6 decimals.` } };
|
|
897
|
-
}
|
|
898
|
-
const micros = net / divisor;
|
|
899
|
-
subtotal = total = `${micros / 1000000n}.${(micros % 1000000n).toString().padStart(6, "0")}`;
|
|
895
|
+
const net = inclusiveNet(local?.lines.find((stored) => stored.id === line.clientLineId)?.netMicros, line.clientLineId);
|
|
896
|
+
if (typeof net !== "string") return net;
|
|
897
|
+
subtotal = total = net;
|
|
900
898
|
}
|
|
901
|
-
|
|
899
|
+
const custom = line.custom;
|
|
900
|
+
const price = major(line.unitPriceMinor);
|
|
901
|
+
line_items.push(custom ? {
|
|
902
|
+
product_id: 0,
|
|
903
|
+
name: custom.name,
|
|
904
|
+
...custom.sku ? { sku: custom.sku } : {},
|
|
905
|
+
quantity: line.quantity,
|
|
906
|
+
subtotal,
|
|
907
|
+
total,
|
|
908
|
+
tax_class: custom.taxClass ?? "",
|
|
909
|
+
meta_data: [{
|
|
910
|
+
key: "_woocommerce_pos_data",
|
|
911
|
+
value: JSON.stringify({ price, regular_price: price, tax_status: custom.taxStatus })
|
|
912
|
+
}]
|
|
913
|
+
} : { product_id: Number(line.variantId), quantity: line.quantity, subtotal, total });
|
|
914
|
+
}
|
|
915
|
+
const fee_lines = [], shipping_lines = [];
|
|
916
|
+
for (const fee of p.fees ?? []) {
|
|
917
|
+
const total = p.pricesIncludeTax ? inclusiveNet(local?.fees?.find((stored) => stored.id === fee.clientFeeId)?.netMicros, fee.clientFeeId) : major(fee.amountMinor);
|
|
918
|
+
if (typeof total !== "string") return total;
|
|
919
|
+
fee_lines.push({ name: fee.name, total, tax_status: fee.taxStatus, tax_class: fee.taxClass ?? "" });
|
|
920
|
+
}
|
|
921
|
+
for (const shipping of p.shipping ?? []) {
|
|
922
|
+
const total = p.pricesIncludeTax ? inclusiveNet(local?.shipping?.find((stored) => stored.id === shipping.clientShippingId)?.netMicros, shipping.clientShippingId) : major(shipping.amountMinor);
|
|
923
|
+
if (typeof total !== "string") return total;
|
|
924
|
+
shipping_lines.push({ method_id: shipping.methodId ?? "pos", method_title: shipping.name, total });
|
|
902
925
|
}
|
|
903
926
|
const primary = p.payments.reduce((largest, payment) => payment.amountMinor > largest.amountMinor ? payment : largest);
|
|
904
927
|
const cash = primary.method === "cash";
|
|
@@ -920,6 +943,8 @@ function toWooOrderPayload(envelope, local, options) {
|
|
|
920
943
|
payment_method: cash ? "pos_cash" : "pos_card",
|
|
921
944
|
payment_method_title: cash ? "Cash" : "Card",
|
|
922
945
|
line_items,
|
|
946
|
+
...fee_lines.length ? { fee_lines } : {},
|
|
947
|
+
...shipping_lines.length ? { shipping_lines } : {},
|
|
923
948
|
meta_data,
|
|
924
949
|
...p.customer?.customerId && /^\d+$/.test(p.customer.customerId) ? { customer_id: Number(p.customer.customerId) } : {},
|
|
925
950
|
...p.customer?.email ? { billing: { email: p.customer.email } } : {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallyui/connector-woocommerce",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "WooCommerce connector for Tally UI",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"directory": "connectors/woocommerce"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"@tallyui/core": "^3.
|
|
29
|
+
"@tallyui/core": "^3.4.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@tallyui/database": "3.
|
|
32
|
+
"@tallyui/database": "3.4.0",
|
|
33
33
|
"rxdb": "17.5.0"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
@@ -28,13 +28,14 @@ export function wooMinorFromDecimal(text: string, currency: string): number | un
|
|
|
28
28
|
return moneyFromDecimalString(end ? `${whole}.${fraction.slice(0, end)}` : whole, currency)?.amount;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export interface WooLocalOrder {
|
|
31
|
+
export interface WooLocalOrder {
|
|
32
|
+
lines: ReadonlyArray<{ id: string; netMicros?: string }>;
|
|
33
|
+
fees?: ReadonlyArray<{ id: string; netMicros?: string }>;
|
|
34
|
+
shipping?: ReadonlyArray<{ id: string; netMicros?: string }>;
|
|
35
|
+
}
|
|
32
36
|
|
|
33
37
|
export function toWooOrderPayload(envelope: OrderCreateEnvelope, local?: WooLocalOrder, options?: { paymentsList?: boolean }): { payload: Record<string, unknown> } | { error: { code: string; message: string } } {
|
|
34
38
|
const p = envelope.payload;
|
|
35
|
-
if (envelope.version === 5 && (p.fees?.length || p.shipping?.length || p.lines.some((line) => line.custom))) {
|
|
36
|
-
return { error: { code: 'invalid_payload', message: 'Fees, shipping and custom lines are not supported by this connector yet.' } };
|
|
37
|
-
}
|
|
38
39
|
if (p.payments.length === 0 || (p.payments.length > 1 && !options?.paymentsList)) {
|
|
39
40
|
return { error: { code: 'invalid_payload', message: 'WooCommerce orders take one payment.' } };
|
|
40
41
|
}
|
|
@@ -45,35 +46,55 @@ export function toWooOrderPayload(envelope: OrderCreateEnvelope, local?: WooLoca
|
|
|
45
46
|
return { error: { code: 'invalid_payload', message: 'Payments do not add up to the order total.' } };
|
|
46
47
|
}
|
|
47
48
|
for (const line of p.lines) {
|
|
48
|
-
if (!/^[1-9]\d*$/.test(line.variantId ?? '') || !Number.isSafeInteger(Number(line.variantId))) {
|
|
49
|
+
if (!line.custom && (!/^[1-9]\d*$/.test(line.variantId ?? '') || !Number.isSafeInteger(Number(line.variantId)))) {
|
|
49
50
|
return { error: { code: 'invalid_payload', message: `Line ${line.clientLineId} has no WooCommerce product id.` } };
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
const digits = p.display?.exponent ?? minorUnitDigits(p.currency);
|
|
53
54
|
const major = (minor: number) => (minor / 10 ** digits).toFixed(digits);
|
|
55
|
+
const inclusiveNet = (netMicros: string | undefined, id: string) => {
|
|
56
|
+
if (netMicros === undefined) {
|
|
57
|
+
return { error: { code: 'unsupported_tax_mode', message: "Tax-inclusive prices need the till's WooCommerce tax figures; update the till." } };
|
|
58
|
+
}
|
|
59
|
+
const net = BigInt(netMicros), divisor = 10n ** BigInt(digits);
|
|
60
|
+
if (net < 0n) {
|
|
61
|
+
return { error: { code: 'invalid_payload', message: `Line ${id} has a negative net.` } };
|
|
62
|
+
}
|
|
63
|
+
if (net % divisor !== 0n) {
|
|
64
|
+
return { error: { code: 'invalid_payload', message: `Line ${id} has a net finer than 6 decimals.` } };
|
|
65
|
+
}
|
|
66
|
+
const micros = net / divisor;
|
|
67
|
+
return `${micros / 1000000n}.${(micros % 1000000n).toString().padStart(6, '0')}`;
|
|
68
|
+
};
|
|
54
69
|
const line_items = [];
|
|
55
70
|
for (const line of p.lines) {
|
|
56
|
-
let subtotal = major(line.unitPriceMinor * line.quantity);
|
|
57
71
|
let total = major(line.unitPriceMinor * line.quantity - (line.discountMinor ?? 0));
|
|
72
|
+
let subtotal = total;
|
|
58
73
|
if (line.taxInclusive ?? p.pricesIncludeTax) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const netMicros = local?.lines.find((stored) => stored.id === line.clientLineId)?.netMicros;
|
|
63
|
-
if (netMicros === undefined) {
|
|
64
|
-
return { error: { code: 'unsupported_tax_mode', message: "Tax-inclusive prices need the till's WooCommerce tax figures; update the till." } };
|
|
65
|
-
}
|
|
66
|
-
const net = BigInt(netMicros), divisor = 10n ** BigInt(digits);
|
|
67
|
-
if (net < 0n) {
|
|
68
|
-
return { error: { code: 'invalid_payload', message: `Line ${line.clientLineId} has a negative net.` } };
|
|
69
|
-
}
|
|
70
|
-
if (net % divisor !== 0n) {
|
|
71
|
-
return { error: { code: 'invalid_payload', message: `Line ${line.clientLineId} has a net finer than 6 decimals.` } };
|
|
72
|
-
}
|
|
73
|
-
const micros = net / divisor;
|
|
74
|
-
subtotal = total = `${micros / 1000000n}.${(micros % 1000000n).toString().padStart(6, '0')}`;
|
|
74
|
+
const net = inclusiveNet(local?.lines.find((stored) => stored.id === line.clientLineId)?.netMicros, line.clientLineId);
|
|
75
|
+
if (typeof net !== 'string') return net;
|
|
76
|
+
subtotal = total = net;
|
|
75
77
|
}
|
|
76
|
-
|
|
78
|
+
const custom = line.custom;
|
|
79
|
+
const price = major(line.unitPriceMinor);
|
|
80
|
+
line_items.push(custom ? {
|
|
81
|
+
product_id: 0, name: custom.name, ...(custom.sku ? { sku: custom.sku } : {}), quantity: line.quantity, subtotal, total,
|
|
82
|
+
tax_class: custom.taxClass ?? '', meta_data: [{ key: '_woocommerce_pos_data',
|
|
83
|
+
value: JSON.stringify({ price, regular_price: price, tax_status: custom.taxStatus }) }],
|
|
84
|
+
} : { product_id: Number(line.variantId), quantity: line.quantity, subtotal, total });
|
|
85
|
+
}
|
|
86
|
+
const fee_lines = [], shipping_lines = [];
|
|
87
|
+
for (const fee of p.fees ?? []) {
|
|
88
|
+
const total = p.pricesIncludeTax
|
|
89
|
+
? inclusiveNet(local?.fees?.find((stored) => stored.id === fee.clientFeeId)?.netMicros, fee.clientFeeId) : major(fee.amountMinor);
|
|
90
|
+
if (typeof total !== 'string') return total;
|
|
91
|
+
fee_lines.push({ name: fee.name, total, tax_status: fee.taxStatus, tax_class: fee.taxClass ?? '' });
|
|
92
|
+
}
|
|
93
|
+
for (const shipping of p.shipping ?? []) {
|
|
94
|
+
const total = p.pricesIncludeTax
|
|
95
|
+
? inclusiveNet(local?.shipping?.find((stored) => stored.id === shipping.clientShippingId)?.netMicros, shipping.clientShippingId) : major(shipping.amountMinor);
|
|
96
|
+
if (typeof total !== 'string') return total;
|
|
97
|
+
shipping_lines.push({ method_id: shipping.methodId ?? 'pos', method_title: shipping.name, total });
|
|
77
98
|
}
|
|
78
99
|
const primary = p.payments.reduce((largest, payment) => payment.amountMinor > largest.amountMinor ? payment : largest);
|
|
79
100
|
const cash = primary.method === 'cash';
|
|
@@ -91,6 +112,8 @@ export function toWooOrderPayload(envelope: OrderCreateEnvelope, local?: WooLoca
|
|
|
91
112
|
status: 'completed', set_paid: true, currency: p.currency,
|
|
92
113
|
payment_method: cash ? 'pos_cash' : 'pos_card', payment_method_title: cash ? 'Cash' : 'Card',
|
|
93
114
|
line_items,
|
|
115
|
+
...(fee_lines.length ? { fee_lines } : {}),
|
|
116
|
+
...(shipping_lines.length ? { shipping_lines } : {}),
|
|
94
117
|
meta_data,
|
|
95
118
|
...(p.customer?.customerId && /^\d+$/.test(p.customer.customerId) ? { customer_id: Number(p.customer.customerId) } : {}),
|
|
96
119
|
...(p.customer?.email ? { billing: { email: p.customer.email } } : {}),
|
package/src/store-settings.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ConnectorUnauthorizedError, StoreSettingsError, minorUnitDigits, woocommerceTax } from '@tallyui/core';
|
|
2
2
|
import type { ServerCapabilities, StoreSettings, SyncContext } from '@tallyui/core';
|
|
3
3
|
|
|
4
|
-
/** The highest order.create version the WooCommerce transport maps: discounts and
|
|
5
|
-
export const WOO_ORDER_CREATE_VERSION =
|
|
4
|
+
/** The highest order.create version the WooCommerce transport maps: v4's net discounts, and v5's fees, shipping and custom lines (WCPOS push/orders; orders #146, #161). */
|
|
5
|
+
export const WOO_ORDER_CREATE_VERSION = 5;
|
|
6
6
|
|
|
7
7
|
export async function wooStoreSettings(context: SyncContext): Promise<StoreSettings> {
|
|
8
8
|
try {
|