@shushed/helpers 0.0.223-redis-fix-20251222110941 → 0.0.223

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.
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const crypto_1 = __importDefault(require("crypto"));
7
7
  const env_1 = __importDefault(require("./env"));
8
8
  const utils_1 = require("./utils");
9
- const CACHE_EXPIRATION_MS = 1000 * 60 * 60 * 3;
9
+ const CACHE_EXPIRATION_MS = 1000 * 60 * 5;
10
10
  class CentraHelper extends env_1.default {
11
11
  opts;
12
12
  shaToken;
@@ -99,6 +99,12 @@ class CentraHelper extends env_1.default {
99
99
  getCacheKeyForMarket(marketExternalId) {
100
100
  return `${this.getCacheKeyForMarkets()}_${marketExternalId}`;
101
101
  }
102
+ getCacheKeyForCampaigns() {
103
+ return `centra_${this.shaToken}_campaign_name`;
104
+ }
105
+ getCacheKeyForCampaign(campaignName) {
106
+ return `${this.getCacheKeyForCampaigns()}_${campaignName}`;
107
+ }
102
108
  getCacheKeyForSizeCharts() {
103
109
  return `centra_${this.shaToken}_size_chart_external_id`;
104
110
  }
@@ -130,7 +136,7 @@ class CentraHelper extends env_1.default {
130
136
  return `${this.getCacheKeyForCentraWarehouses()}_${warehouseExternalId}`;
131
137
  }
132
138
  getCacheKeyForCentraPricelists() {
133
- return `centra_${this.shaToken}_pricelist_external_id`;
139
+ return `centra_${this.shaToken}_pricelists_external_id`;
134
140
  }
135
141
  getCacheKeyForCentraPricelist(pricelistExternalId) {
136
142
  return `${this.getCacheKeyForCentraPricelists()}_${pricelistExternalId}`;
@@ -218,7 +224,7 @@ class CentraHelper extends env_1.default {
218
224
  return result;
219
225
  }
220
226
  async fetchCentraCampaigns(names) {
221
- const limit = (names?.length || 0) > 200 ? 200 : (names?.length || 0);
227
+ const limit = names ? (names.length > 200 ? 200 : names.length) : 200;
222
228
  let nextCursor = null;
223
229
  const result = {};
224
230
  do {
@@ -270,7 +276,7 @@ class CentraHelper extends env_1.default {
270
276
  nextCursor = null;
271
277
  }
272
278
  if (campaignConnection && campaignConnection.edges?.length) {
273
- for (let i = campaignConnection.edges.length; i < (names?.length || 0); i++) {
279
+ for (let i = 0; i < campaignConnection.edges.length; i++) {
274
280
  const { node } = campaignConnection.edges[i];
275
281
  result[node.name] = node;
276
282
  }
@@ -721,7 +727,9 @@ class CentraHelper extends env_1.default {
721
727
  }
722
728
  else {
723
729
  for (const warehouse of warehouses) {
724
- warehouseToSet[warehouse.externalId] = warehouse;
730
+ if (warehouse.externalId) {
731
+ warehouseToSet[warehouse.externalId] = warehouse;
732
+ }
725
733
  }
726
734
  await this.set(Object.entries(warehouseToSet).filter(([_, value]) => !(value instanceof Error)).map(([key, value]) => ({ name: this.getCacheKeyForCentraWarehouse(key), value: JSON.stringify(value) })), 'env', {
727
735
  ephemeralMs: CACHE_EXPIRATION_MS,
@@ -797,6 +805,49 @@ class CentraHelper extends env_1.default {
797
805
  }
798
806
  return Object.assign({}, pricelistInCache, pricelistToSet);
799
807
  }
808
+ async getCentraCampaigns(alwaysFetch = false) {
809
+ let campaignInCache = {};
810
+ let dedupedCampaignNamesInCache = [];
811
+ let campaignsToFetch = null;
812
+ if (!alwaysFetch) {
813
+ const campaignNamesInCache = await (this.get(this.getCacheKeyForCampaigns(), 'env', {
814
+ isEphemeral: true,
815
+ encrypted: false,
816
+ }).then(x => x ? JSON.parse(x) : null));
817
+ if (campaignNamesInCache) {
818
+ dedupedCampaignNamesInCache = campaignNamesInCache.filter((x, index, self) => self.indexOf(x) === index);
819
+ campaignInCache = Object.fromEntries(Object.entries(await this.get(dedupedCampaignNamesInCache.map((x) => this.getCacheKeyForCampaign(x)), 'env', {
820
+ isEphemeral: true,
821
+ encrypted: false,
822
+ })).map(([key, value]) => [key, value ? JSON.parse(value || 'null') : undefined]).filter(([_, value]) => value));
823
+ campaignsToFetch = dedupedCampaignNamesInCache.filter(x => !campaignInCache[x]);
824
+ }
825
+ }
826
+ const campaignToSet = {};
827
+ if (!campaignsToFetch || campaignsToFetch.length) {
828
+ const campaigns = await this.fetchCentraCampaigns();
829
+ if (CentraHelper.isCentraErrors(campaigns)) {
830
+ return new Error(`Failed to fetch campaigns: ${campaigns.errors.map((x) => x.message).join(', ')}`);
831
+ }
832
+ else {
833
+ for (const campaign of Object.values(campaigns)) {
834
+ campaignToSet[campaign.name] = campaign;
835
+ }
836
+ await this.set(Object.entries(campaignToSet).filter(([_, value]) => !(value instanceof Error)).map(([key, value]) => ({ name: this.getCacheKeyForCampaign(key), value: JSON.stringify(value) })), 'env', {
837
+ ephemeralMs: CACHE_EXPIRATION_MS,
838
+ encrypted: false,
839
+ });
840
+ await this.set([{
841
+ name: this.getCacheKeyForCampaigns(),
842
+ value: JSON.stringify(Object.keys(campaignToSet)),
843
+ }], 'env', {
844
+ ephemeralMs: CACHE_EXPIRATION_MS,
845
+ encrypted: false,
846
+ });
847
+ }
848
+ }
849
+ return Object.assign({}, campaignInCache, campaignToSet);
850
+ }
800
851
  async getCentraMarkets(alwaysFetch = false) {
801
852
  let marketInCache = {};
802
853
  let dedupedMarketNamesInCache = [];
@@ -155,15 +155,12 @@ class EnvEngine extends runtime_1.default {
155
155
  Object.assign(this.globalInMemoryRef[level], Object.fromEntries(Object.entries(objEncrypted).map(([k, v]) => [k, `${expirseAt}/${now}/${v}`])));
156
156
  }
157
157
  if (!options.ignoreStores?.includes('redis')) {
158
- try {
158
+ (async () => {
159
159
  const redisClient = await (0, redisClient_1.getConnectedRedisClient)(this.systemEnvName).catch(() => null);
160
160
  if (redisClient) {
161
- await Promise.allSettled(Object.entries(objEncrypted).map(([k, v]) => redisClient.set(k, `${expirseAt}/${now}/${v}`, { PX: expirseAt - Date.now() })));
161
+ Promise.allSettled(Object.entries(objEncrypted).map(([k, v]) => redisClient.set(k, `${expirseAt}/${now}/${v}`, { PX: expirseAt - Date.now() })));
162
162
  }
163
- }
164
- catch {
165
- this.logging.error(`Failed to set the ${envs.map(x => x.name).join(', ')} in Redis`);
166
- }
163
+ })().catch(() => this.logging.error(`Failed to set the ${envs.map(x => x.name).join(', ')} in Redis`));
167
164
  }
168
165
  }
169
166
  else {
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.RedisConnectionError = exports.RateLimit = exports.setHeaders = exports.BCOrderHelper = exports.DatoHelper = exports.AirtableHelper = exports.CentraHelper = exports.BigQueryHelper = exports.JWKSHelper = exports.CloudTasksHelper = exports.Secrets = exports.SchedulerHelper = exports.Logging = exports.Runtime = exports.PubSubHelper = exports.EnvEngine = exports.validate = void 0;
20
+ exports.SitooHelper = exports.RedisConnectionError = exports.RateLimit = exports.setHeaders = exports.BCOrderHelper = exports.DatoHelper = exports.AirtableHelper = exports.CentraHelper = exports.BigQueryHelper = exports.JWKSHelper = exports.CloudTasksHelper = exports.Secrets = exports.SchedulerHelper = exports.Logging = exports.Runtime = exports.PubSubHelper = exports.EnvEngine = exports.validate = void 0;
21
21
  var validate_1 = require("./validate");
22
22
  Object.defineProperty(exports, "validate", { enumerable: true, get: function () { return __importDefault(validate_1).default; } });
23
23
  __exportStar(require("./sanitize"), exports);
@@ -52,3 +52,5 @@ Object.defineProperty(exports, "setHeaders", { enumerable: true, get: function (
52
52
  var rateLimit_1 = require("./rateLimit");
53
53
  Object.defineProperty(exports, "RateLimit", { enumerable: true, get: function () { return __importDefault(rateLimit_1).default; } });
54
54
  Object.defineProperty(exports, "RedisConnectionError", { enumerable: true, get: function () { return rateLimit_1.RedisConnectionError; } });
55
+ var sitoo_1 = require("./sitoo");
56
+ Object.defineProperty(exports, "SitooHelper", { enumerable: true, get: function () { return __importDefault(sitoo_1).default; } });
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const crypto_1 = __importDefault(require("crypto"));
7
+ const lodash_groupby_1 = __importDefault(require("lodash.groupby"));
8
+ const env_1 = __importDefault(require("./env"));
9
+ const SITOO_TR_TYPE_MANUAL_IN = 10;
10
+ const SITOO_TR_TYPE_MANUAL_OUT = 20;
11
+ const BATCH_SIZE = 900;
12
+ class SitooHelper extends env_1.default {
13
+ opts;
14
+ shaToken;
15
+ baseUrl;
16
+ siteId;
17
+ constructor(options, opts) {
18
+ super(options);
19
+ this.opts = opts;
20
+ this.shaToken = crypto_1.default.createHash('sha256').update(opts.accessToken).digest('hex').slice(0, 8);
21
+ this.baseUrl = opts.sitooBaseUrl.replace(/\/$/, '');
22
+ this.siteId = opts.sitooSiteId;
23
+ }
24
+ async getSitooWarehouses() {
25
+ const url = `${this.baseUrl}/sites/${this.siteId}/warehouses.json`;
26
+ const response = await fetch(url, {
27
+ method: 'GET',
28
+ headers: {
29
+ 'Authorization': `Basic ${this.opts.accessToken}`,
30
+ 'Content-Type': 'application/json',
31
+ },
32
+ });
33
+ if (!response.ok) {
34
+ const errorText = await response.text().catch(() => 'Unknown error');
35
+ throw new Error(`Sitoo API error: ${response.status} ${response.statusText} - ${errorText}`);
36
+ }
37
+ const data = await response.json();
38
+ const nameToId = {};
39
+ const warehouses = {};
40
+ for (const warehouse of data.items) {
41
+ nameToId[warehouse.name] = warehouse.warehouseid;
42
+ warehouses[warehouse.warehouseid] = warehouse;
43
+ }
44
+ return { nameToId, warehouses };
45
+ }
46
+ async fetchWarehouseTransactionsWithFilter(params) {
47
+ const queryParams = new URLSearchParams();
48
+ queryParams.set('num', (params.num || 100).toString());
49
+ if (params.transactiontype !== undefined) {
50
+ queryParams.set('transactiontype', params.transactiontype.toString());
51
+ }
52
+ if (params.datecreatedfrom !== undefined) {
53
+ queryParams.set('datecreatedfrom', params.datecreatedfrom.toString());
54
+ }
55
+ if (params.start !== undefined) {
56
+ queryParams.set('start', params.start.toString());
57
+ }
58
+ queryParams.set('sort', params.ascending ? 'warehousetransactionid' : '-warehousetransactionid');
59
+ const url = `${this.baseUrl}/sites/${this.siteId}/warehouses/${params.warehouseid}/warehousetransactions.json?${queryParams.toString()}`;
60
+ const response = await fetch(url, {
61
+ method: 'GET',
62
+ headers: {
63
+ 'Authorization': `Basic ${this.opts.accessToken}`,
64
+ 'Content-Type': 'application/json',
65
+ },
66
+ });
67
+ if (!response.ok) {
68
+ const errorText = await response.text().catch(() => 'Unknown error');
69
+ throw new Error(`Sitoo API error: ${response.status} ${response.statusText} - ${errorText}`);
70
+ }
71
+ return await response.json();
72
+ }
73
+ async searchTransactionsInApi(warehouseId, entryNosToFind, transactionType, datecreatedfrom) {
74
+ const found = new Map();
75
+ let lowestTransactionId = undefined;
76
+ if (entryNosToFind.size === 0) {
77
+ return { found, lowestTransactionId };
78
+ }
79
+ let hasMore = true;
80
+ const pageSize = 100;
81
+ const currentDateFrom = datecreatedfrom;
82
+ let currentStart = 0;
83
+ while (hasMore && found.size < entryNosToFind.size) {
84
+ const envelope = await this.fetchWarehouseTransactionsWithFilter({
85
+ warehouseid: warehouseId,
86
+ datecreatedfrom: currentDateFrom,
87
+ transactiontype: transactionType,
88
+ ascending: false,
89
+ num: pageSize,
90
+ start: currentStart,
91
+ });
92
+ const transactions = envelope.items;
93
+ if (transactions.length === 0) {
94
+ hasMore = false;
95
+ break;
96
+ }
97
+ for (const transaction of transactions) {
98
+ if (lowestTransactionId === undefined || transaction.warehousetransactionid < lowestTransactionId) {
99
+ lowestTransactionId = transaction.warehousetransactionid;
100
+ }
101
+ if (transaction.description) {
102
+ for (const entryNo of entryNosToFind) {
103
+ if (!found.has(entryNo) && transaction.description.includes(`'${entryNo}'`)) {
104
+ found.set(entryNo, transaction);
105
+ }
106
+ }
107
+ }
108
+ if (found.size === entryNosToFind.size) {
109
+ break;
110
+ }
111
+ }
112
+ currentStart = currentStart ? currentStart + transactions.length : transactions.length;
113
+ if (transactions.length < pageSize) {
114
+ hasMore = false;
115
+ }
116
+ }
117
+ return { found, lowestTransactionId };
118
+ }
119
+ async batchAddWarehouseTransactions(transactions) {
120
+ if (transactions.length === 0)
121
+ return [];
122
+ if (transactions.length > BATCH_SIZE) {
123
+ throw new Error(`Batch size exceeds maximum of ${BATCH_SIZE}. Got ${transactions.length}`);
124
+ }
125
+ const url = `${this.baseUrl}/sites/${this.siteId}/warehousetransactions.json`;
126
+ const response = await fetch(url, {
127
+ method: 'POST',
128
+ headers: {
129
+ 'Authorization': `Basic ${this.opts.accessToken}`,
130
+ 'Content-Type': 'application/json',
131
+ },
132
+ body: JSON.stringify(transactions),
133
+ });
134
+ if (!response.ok) {
135
+ const errorText = await response.text().catch(() => 'Unknown error');
136
+ throw new Error(`Sitoo API error: ${response.status} ${response.statusText} - ${errorText}`);
137
+ }
138
+ const result = await response.json();
139
+ return result;
140
+ }
141
+ async syncWarehouseTransactions(items, options) {
142
+ if (items.length === 0) {
143
+ return [];
144
+ }
145
+ const locationCodeToWarehouse = (await this.getSitooWarehouses()).nameToId;
146
+ const foundEntryNos = new Map();
147
+ const results = {};
148
+ const entryNoToIdx = {};
149
+ const entriesByWarehouseAndTransactionType = new Map();
150
+ for (let i = 0; i < items.length; i++) {
151
+ const entry = items[i];
152
+ const warehouseId = locationCodeToWarehouse[entry.location_code];
153
+ const transactionType = entry.type === 'transfer' ? (entry.quantity > 0 ? SITOO_TR_TYPE_MANUAL_IN : SITOO_TR_TYPE_MANUAL_OUT) : undefined;
154
+ entryNoToIdx[entry.entry_no] = i;
155
+ if (transactionType === undefined) {
156
+ results[i] = {
157
+ error: false,
158
+ message: `Not supported transaction type: ${entry.type}`,
159
+ };
160
+ continue;
161
+ }
162
+ if (warehouseId === undefined) {
163
+ results[i] = {
164
+ error: false,
165
+ message: `Not supported warehouse in Sitoo: ${entry.location_code}`,
166
+ };
167
+ continue;
168
+ }
169
+ const key = `${warehouseId}-${transactionType}`;
170
+ if (!entriesByWarehouseAndTransactionType.has(key)) {
171
+ entriesByWarehouseAndTransactionType.set(key, []);
172
+ }
173
+ entriesByWarehouseAndTransactionType.get(key).push(entry);
174
+ }
175
+ for (const [_, warehouseEntries] of entriesByWarehouseAndTransactionType) {
176
+ if (warehouseEntries.length > 0) {
177
+ let datecreatedfrom = undefined;
178
+ for (const entry of warehouseEntries) {
179
+ const entryCreatedAt = Math.floor(new Date(entry.created_at).getTime() / 1000);
180
+ if (datecreatedfrom === undefined || entryCreatedAt < datecreatedfrom) {
181
+ datecreatedfrom = entryCreatedAt;
182
+ }
183
+ }
184
+ const { found: apiFound } = await this.searchTransactionsInApi(locationCodeToWarehouse[warehouseEntries[0].location_code], new Set(warehouseEntries.map(e => e.entry_no.toString())), warehouseEntries[0].quantity > 0 ? SITOO_TR_TYPE_MANUAL_IN : SITOO_TR_TYPE_MANUAL_OUT, datecreatedfrom);
185
+ for (const [entryNo, transaction] of apiFound) {
186
+ foundEntryNos.set(entryNo, transaction.warehousetransactionid);
187
+ }
188
+ }
189
+ }
190
+ for (const [entryNo, transactionId] of foundEntryNos) {
191
+ const idx = entryNoToIdx[entryNo];
192
+ results[idx] = {
193
+ error: false,
194
+ message: `Found transaction in Sitoo: ${transactionId} for the entry ${entryNo}`,
195
+ };
196
+ }
197
+ const batches = [[]];
198
+ for (const [_, warehouseEntries] of entriesByWarehouseAndTransactionType) {
199
+ for (let i = 0; i < warehouseEntries.length; i += 1) {
200
+ if (!foundEntryNos.has(warehouseEntries[i].entry_no)) {
201
+ if ((batches[batches.length - 1].length + 1) >= BATCH_SIZE) {
202
+ batches.push([]);
203
+ }
204
+ batches[batches.length - 1].push(warehouseEntries[i]);
205
+ }
206
+ }
207
+ }
208
+ const hasMissingEntries = batches[0].length > 0;
209
+ if (!options?.preview && hasMissingEntries) {
210
+ for (let i = 0; i < batches.length; i++) {
211
+ const warehouseEntities = (0, lodash_groupby_1.default)(batches[i], e => `${locationCodeToWarehouse[e.location_code]}-${e.quantity > 0 ? 'positive' : 'negative'}`);
212
+ const entryNosInBatches = {};
213
+ const transactionsToCreate = [];
214
+ for (const k in warehouseEntities) {
215
+ const entriesToCreate = warehouseEntities[k];
216
+ const warehouseId = locationCodeToWarehouse[entriesToCreate[0].location_code];
217
+ const entryType = entriesToCreate[0].quantity > 0 ? SITOO_TR_TYPE_MANUAL_IN : SITOO_TR_TYPE_MANUAL_OUT;
218
+ entryNosInBatches[transactionsToCreate.length] = entriesToCreate.map(e => e.entry_no);
219
+ transactionsToCreate.push({
220
+ warehouseid: warehouseId,
221
+ transactiontype: entryType,
222
+ description: entriesToCreate.map(e => `'${e.entry_no}'`).join(', '),
223
+ items: entriesToCreate.map(e => ({
224
+ sku: [e.style_id, e.colour_id, e.size_code].filter(Boolean).join('-'),
225
+ decimalquantity: `${e.quantity.toFixed(3)}`,
226
+ moneypricein: (((e.unit_cost?.value ?? 0) / 100) * e.quantity).toFixed(2),
227
+ })),
228
+ });
229
+ }
230
+ try {
231
+ const createdIds = await this.batchAddWarehouseTransactions(transactionsToCreate);
232
+ for (let j = 0; j < transactionsToCreate.length; j++) {
233
+ const transactionId = createdIds[j];
234
+ for (let k = 0; k < entryNosInBatches[j].length; k += 1) {
235
+ const entryNo = entryNosInBatches[j][k];
236
+ const idx = entryNoToIdx[entryNo];
237
+ results[idx] = {
238
+ entryNo: entryNo,
239
+ transactionId: transactionId,
240
+ };
241
+ }
242
+ }
243
+ }
244
+ catch (error) {
245
+ for (const entry of batches[i]) {
246
+ const idx = entryNoToIdx[entry.entry_no];
247
+ results[idx] = error;
248
+ }
249
+ }
250
+ }
251
+ }
252
+ else {
253
+ for (let i = 0; i < batches.length; i++) {
254
+ for (let j = 0; j < batches[i].length; j += 1) {
255
+ const entry = batches[i][j];
256
+ const idx = entryNoToIdx[entry.entry_no];
257
+ const warehouseId = locationCodeToWarehouse[entry.location_code];
258
+ const transactionType = entry.quantity > 0 ? SITOO_TR_TYPE_MANUAL_IN : SITOO_TR_TYPE_MANUAL_OUT;
259
+ results[idx] = {
260
+ error: false,
261
+ message: `In Preview Mode. ${entry.entry_no} scheduled to be created as transction type: ${transactionType} in the warehouse: ${warehouseId}. Batch: ${i}`
262
+ };
263
+ }
264
+ }
265
+ }
266
+ const resultsAsArray = [];
267
+ for (let i = 0; i < items.length; i += 1) {
268
+ const result = results[i];
269
+ if (!result) {
270
+ resultsAsArray.push(new Error(`${items[i].entry_no} got missed in processing`));
271
+ }
272
+ else {
273
+ resultsAsArray.push(result);
274
+ }
275
+ }
276
+ return resultsAsArray;
277
+ }
278
+ }
279
+ exports.default = SitooHelper;
package/dist/package.json CHANGED
@@ -5,6 +5,7 @@
5
5
  "license": "UNLICENSED",
6
6
  "description": "",
7
7
  "dependencies": {
8
+ "@google-cloud/firestore": "^7.11.1",
8
9
  "@hackylabs/deep-redact": "^2.2.1",
9
10
  "ajv": "^8.17.1",
10
11
  "ajv-formats": "^3.0.1",
@@ -12,15 +13,15 @@
12
13
  "jose": "^6.0.11",
13
14
  "lodash.chunk": "^4.2.0",
14
15
  "lodash.clonedeep": "^4.5.0",
16
+ "lodash.groupby": "^4.6.0",
15
17
  "lodash.isequal": "^4.5.0",
16
18
  "lodash.omit": "^4.5.0",
17
19
  "lodash.pick": "^4.4.0",
18
20
  "mime-types": "^3.0.1",
19
21
  "p-limit": "^7.1.1",
20
22
  "rate-limiter-flexible": "^7.2.0",
21
- "uuid": "^11.1.0",
22
23
  "redis": "^5.6.0",
23
- "@google-cloud/firestore": "^7.11.1"
24
+ "uuid": "^11.1.0"
24
25
  },
25
26
  "files": [
26
27
  "dist"
@@ -10,6 +10,8 @@ export { default as DevelopmentColour } from './development-colour.schema.json';
10
10
  export { default as Asset } from './asset.schema.json';
11
11
  export { default as CustomerSegment } from './customer-segment.schema.json';
12
12
  export { default as MarketingPref } from './marketing-preferences.schema.json';
13
+ export { default as StockMovement } from './stock-movement.schema.json';
14
+ export { default as PurchaseOrderline } from './purchase-orderline.schema.json';
13
15
  export * from './order';
14
16
  export { default as Order } from './order.schema.json';
15
17
  export * from './messages';
@@ -10,6 +10,8 @@ export { default as Price } from './price';
10
10
  export { default as ProductCategory } from './product-category';
11
11
  export { default as ProductDraft } from './product-draft';
12
12
  export { default as Product } from './product';
13
+ export { default as PurchaseOrderline } from './purchase-orderline';
14
+ export { default as StockMovement } from './stock-movement';
13
15
  export { default as Stock } from './stock';
14
16
  export { default as Total } from './total';
15
17
  export * as Messages from './messages';
@@ -0,0 +1,110 @@
1
+ declare const schema: {
2
+ readonly $schema: "http://json-schema.org/draft-07/schema#";
3
+ readonly title: "Stock Movement Schema";
4
+ readonly type: "object";
5
+ readonly additionalProperties: false;
6
+ readonly properties: {
7
+ readonly style_id: {
8
+ readonly type: "string";
9
+ readonly minLength: 1;
10
+ };
11
+ readonly colour_id: {
12
+ readonly type: "string";
13
+ readonly minLength: 1;
14
+ };
15
+ readonly product_id: {
16
+ readonly type: "string";
17
+ readonly minLength: 1;
18
+ };
19
+ readonly size_code: {
20
+ readonly type: "string";
21
+ readonly minLength: 1;
22
+ };
23
+ readonly sku: {
24
+ readonly type: "string";
25
+ readonly minLength: 1;
26
+ };
27
+ readonly season_id: {
28
+ readonly type: "string";
29
+ };
30
+ readonly drop: {
31
+ readonly type: "string";
32
+ };
33
+ readonly document_line_no: {
34
+ readonly type: "string";
35
+ };
36
+ readonly document_no: {
37
+ readonly type: "string";
38
+ };
39
+ readonly created_at: {
40
+ readonly type: "string";
41
+ readonly format: "date-time";
42
+ };
43
+ readonly location_code: {
44
+ readonly type: "string";
45
+ };
46
+ readonly quantity: {
47
+ readonly type: "number";
48
+ };
49
+ readonly quantity_received: {
50
+ readonly type: "number";
51
+ };
52
+ readonly quantity_to_receive: {
53
+ readonly type: "number";
54
+ };
55
+ readonly last_modified_at: {
56
+ readonly type: "string";
57
+ readonly format: "date-time";
58
+ };
59
+ readonly expected_date: {
60
+ readonly type: "string";
61
+ readonly format: "date-time";
62
+ };
63
+ readonly unit_price: {
64
+ readonly oneOf: readonly [{
65
+ readonly $schema: "http://json-schema.org/draft-07/schema#";
66
+ readonly title: "Money";
67
+ readonly type: "object";
68
+ readonly additionalProperties: false;
69
+ readonly properties: {
70
+ readonly value: {
71
+ readonly type: "integer";
72
+ readonly minimum: 0;
73
+ };
74
+ readonly decimal_places: {
75
+ readonly type: "integer";
76
+ readonly minimum: 0;
77
+ readonly maximum: 4;
78
+ };
79
+ readonly currency: {
80
+ readonly title: "Currency";
81
+ readonly $schema: "http://json-schema.org/draft-07/schema#";
82
+ readonly type: "string";
83
+ readonly enum: readonly ["AFN", "ALL", "DZD", "USD", "EUR", "AOA", "XCD", "ARS", "AMD", "AWG", "AUD", "AZN", "BSD", "BHD", "BDT", "BBD", "BYN", "BZD", "XOF", "BMD", "BTN", "INR", "BOB", "BOV", "BAM", "BWP", "NOK", "BRL", "BND", "BGN", "BIF", "CVE", "KHR", "XAF", "CAD", "KYD", "CLF", "CLP", "CNY", "COP", "COU", "KMF", "CDF", "NZD", "CRC", "CUC", "CUP", "ANG", "CZK", "DKK", "DJF", "DOP", "EGP", "SVC", "ERN", "ETB", "FKP", "FJD", "XPF", "GMD", "GEL", "GHS", "GIP", "GTQ", "GBP", "GNF", "GYD", "HTG", "HNL", "HKD", "HUF", "ISK", "IDR", "XDR", "IRR", "IQD", "ILS", "JMD", "JPY", "JOD", "KZT", "KES", "KPW", "KRW", "KWD", "KGS", "LAK", "LBP", "LSL", "ZAR", "LRD", "LYD", "CHF", "MOP", "MGA", "MWK", "MYR", "MVR", "MRU", "MUR", "XUA", "MXN", "MXV", "MDL", "MNT", "MAD", "MZN", "MMK", "NAD", "NPR", "NIO", "NGN", "OMR", "PKR", "PAB", "PGK", "PYG", "PEN", "PHP", "PLN", "QAR", "MKD", "RON", "RUB", "RWF", "SHP", "WST", "STN", "SAR", "RSD", "SCR", "SLE", "SGD", "XSU", "SBD", "SOS", "SSP", "LKR", "SDG", "SRD", "SZL", "SEK", "CHE", "CHW", "SYP", "TWD", "TJS", "TZS", "THB", "TOP", "TTD", "TND", "TRY", "TMT", "UGX", "UAH", "AED", "USN", "UYI", "UYU", "UZS", "VUV", "VEF", "VED", "VND", "YER", "ZMW", "ZWL"];
84
+ };
85
+ readonly lcy_value: {
86
+ readonly type: "integer";
87
+ readonly minimum: 0;
88
+ };
89
+ readonly lcy_currency: {
90
+ readonly title: "LCY Currency";
91
+ readonly $schema: "http://json-schema.org/draft-07/schema#";
92
+ readonly type: "string";
93
+ readonly enum: readonly ["AFN", "ALL", "DZD", "USD", "EUR", "AOA", "XCD", "ARS", "AMD", "AWG", "AUD", "AZN", "BSD", "BHD", "BDT", "BBD", "BYN", "BZD", "XOF", "BMD", "BTN", "INR", "BOB", "BOV", "BAM", "BWP", "NOK", "BRL", "BND", "BGN", "BIF", "CVE", "KHR", "XAF", "CAD", "KYD", "CLF", "CLP", "CNY", "COP", "COU", "KMF", "CDF", "NZD", "CRC", "CUC", "CUP", "ANG", "CZK", "DKK", "DJF", "DOP", "EGP", "SVC", "ERN", "ETB", "FKP", "FJD", "XPF", "GMD", "GEL", "GHS", "GIP", "GTQ", "GBP", "GNF", "GYD", "HTG", "HNL", "HKD", "HUF", "ISK", "IDR", "XDR", "IRR", "IQD", "ILS", "JMD", "JPY", "JOD", "KZT", "KES", "KPW", "KRW", "KWD", "KGS", "LAK", "LBP", "LSL", "ZAR", "LRD", "LYD", "CHF", "MOP", "MGA", "MWK", "MYR", "MVR", "MRU", "MUR", "XUA", "MXN", "MXV", "MDL", "MNT", "MAD", "MZN", "MMK", "NAD", "NPR", "NIO", "NGN", "OMR", "PKR", "PAB", "PGK", "PYG", "PEN", "PHP", "PLN", "QAR", "MKD", "RON", "RUB", "RWF", "SHP", "WST", "STN", "SAR", "RSD", "SCR", "SLE", "SGD", "XSU", "SBD", "SOS", "SSP", "LKR", "SDG", "SRD", "SZL", "SEK", "CHE", "CHW", "SYP", "TWD", "TJS", "TZS", "THB", "TOP", "TTD", "TND", "TRY", "TMT", "UGX", "UAH", "AED", "USN", "UYI", "UYU", "UZS", "VUV", "VEF", "VED", "VND", "YER", "ZMW", "ZWL"];
94
+ };
95
+ readonly lcy_decimal_places: {
96
+ readonly type: "integer";
97
+ readonly minimum: 0;
98
+ readonly maximum: 4;
99
+ };
100
+ };
101
+ readonly required: readonly ["value", "currency", "lcy_value", "lcy_currency", "decimal_places", "lcy_decimal_places"];
102
+ }, {
103
+ readonly type: "null";
104
+ }];
105
+ };
106
+ };
107
+ readonly required: readonly ["document_no", "document_line_no", "style_id", "colour_id", "size_code", "sku", "product_id", "season_id", "drop"];
108
+ readonly $id: "https://shushed.example.com/stock-move.schema.json";
109
+ };
110
+ export default schema;