mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 10:05:24 +02:00
feat(bc): sync pricing units2
This commit is contained in:
+2
-1
@@ -15,7 +15,8 @@ BC_ITEMS_WRITE_METHOD="PATCH"
|
||||
BC_ITEMS_WRITE_URL_TEMPLATE="{{itemsUrl}}('{{itemNo}}')"
|
||||
BC_ITEMS_WRITE_BODY_TEMPLATE=''
|
||||
BC_UOM_WRITE_METHOD="PATCH"
|
||||
BC_UOM_WRITE_URL_TEMPLATE="{{itemUnitsOfMeasureUrl}}('{{itemNo}}')"
|
||||
BC_UOM_CODE="OUTER"
|
||||
BC_UOM_WRITE_URL_TEMPLATE="{{itemUnitsOfMeasureUrl}}(itemNo='{{itemNo}}',code='{{itemUnitsCode}}')"
|
||||
BC_UOM_WRITE_BODY_TEMPLATE=''
|
||||
|
||||
# APP_URL: The URL where this applet is hosted.
|
||||
|
||||
@@ -22,6 +22,6 @@ View your app in AI Studio: https://ai.studio/apps/bac9908e-4996-4e4c-8ec7-3add5
|
||||
`BC_WRITE_METHOD`, `BC_WRITE_URL_TEMPLATE`, `BC_WRITE_BODY_TEMPLATE`
|
||||
5. For the safer BC sync preview/apply flow, you can also set:
|
||||
`BC_ITEMS_WRITE_METHOD`, `BC_ITEMS_WRITE_URL_TEMPLATE`, `BC_ITEMS_WRITE_BODY_TEMPLATE`,
|
||||
`BC_UOM_WRITE_METHOD`, `BC_UOM_WRITE_URL_TEMPLATE`, `BC_UOM_WRITE_BODY_TEMPLATE`
|
||||
`BC_UOM_CODE`, `BC_UOM_WRITE_METHOD`, `BC_UOM_WRITE_URL_TEMPLATE`, `BC_UOM_WRITE_BODY_TEMPLATE`
|
||||
6. Run the app:
|
||||
`npm run dev`
|
||||
|
||||
+6
-1
@@ -16,8 +16,9 @@ export function getBcConfig(env = process.env) {
|
||||
itemsWriteMethod: String(env.BC_ITEMS_WRITE_METHOD || legacyWriteMethod).toUpperCase(),
|
||||
itemsWriteUrlTemplate: env.BC_ITEMS_WRITE_URL_TEMPLATE || legacyWriteUrlTemplate,
|
||||
itemsWriteBodyTemplate: env.BC_ITEMS_WRITE_BODY_TEMPLATE || null,
|
||||
itemUnitsCode: env.BC_UOM_CODE || 'OUTER',
|
||||
itemUnitsWriteMethod: env.BC_UOM_WRITE_METHOD ? String(env.BC_UOM_WRITE_METHOD).toUpperCase() : 'PATCH',
|
||||
itemUnitsWriteUrlTemplate: env.BC_UOM_WRITE_URL_TEMPLATE || `{{itemUnitsOfMeasureUrl}}('{{itemNo}}')`,
|
||||
itemUnitsWriteUrlTemplate: env.BC_UOM_WRITE_URL_TEMPLATE || `{{itemUnitsOfMeasureUrl}}(itemNo='{{itemNo}}',code='{{itemUnitsCode}}')`,
|
||||
itemUnitsWriteBodyTemplate: env.BC_UOM_WRITE_BODY_TEMPLATE || null,
|
||||
};
|
||||
}
|
||||
@@ -30,6 +31,10 @@ export function getItemsUrl(config) {
|
||||
return `https://api.businesscentral.dynamics.com/v2.0/${config.tenantId}/production/api/craze/integrations/v1.0/companies(${config.companyId})/items`;
|
||||
}
|
||||
|
||||
export function getItemUnitsOfMeasureUrl(config) {
|
||||
return `https://api.businesscentral.dynamics.com/v2.0/${config.tenantId}/production/api/craze/integrations/v1.0/companies(${config.companyId})/itemUnitsOfMeasure2`;
|
||||
}
|
||||
|
||||
let tokenCache = { token: null, expiresAt: 0 };
|
||||
|
||||
export async function getBCToken(config) {
|
||||
|
||||
+36
-34
@@ -1,9 +1,5 @@
|
||||
import crypto from 'crypto';
|
||||
import { getBcConfig, getBCToken, getItemsUrl } from './bc-runtime.js';
|
||||
|
||||
function getItemUnitsOfMeasureUrl(config) {
|
||||
return `https://api.businesscentral.dynamics.com/v2.0/${config.tenantId}/production/api/craze/integrations/v1.0/companies(${config.companyId})/itemUnitsOfMeasure`;
|
||||
}
|
||||
import { getBcConfig, getBCToken, getItemsUrl, getItemUnitsOfMeasureUrl } from './bc-runtime.js';
|
||||
|
||||
function findHeaderIndex(headers, patterns) {
|
||||
const normalized = headers.map(h => String(h || '').toLowerCase());
|
||||
@@ -89,13 +85,11 @@ export function buildBusinessCentralMappingPreview(headers, row) {
|
||||
|
||||
const itemUnitsOfMeasurePayload = {
|
||||
itemNo: getValue(row, articleNoIdx),
|
||||
qtyPerUnitOfMeasure6: toBcDecimal(getValue(row, unitsOuterIdx)),
|
||||
width4: toBcDecimal(getValue(row, innerWIdx)),
|
||||
length4: toBcDecimal(getValue(row, innerLIdx)),
|
||||
height4: toBcDecimal(getValue(row, innerHIdx)),
|
||||
width6: toBcDecimal(getValue(row, outerWIdx)),
|
||||
length6: toBcDecimal(getValue(row, outerLIdx)),
|
||||
height6: toBcDecimal(getValue(row, outerHIdx)),
|
||||
code: 'OUTER',
|
||||
qtyPerUnitOfMeasure: toBcDecimal(getValue(row, unitsOuterIdx)),
|
||||
width: toBcDecimal(getValue(row, outerWIdx)),
|
||||
length: toBcDecimal(getValue(row, outerLIdx)),
|
||||
height: toBcDecimal(getValue(row, outerHIdx)),
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -115,13 +109,10 @@ export function buildBusinessCentralMappingPreview(headers, row) {
|
||||
],
|
||||
itemUnitsFields: [
|
||||
makeFieldPreview('Article No.', articleNoIdx, 'itemNo', itemUnitsOfMeasurePayload.itemNo),
|
||||
makeFieldPreview('Units Outer', unitsOuterIdx, 'qtyPerUnitOfMeasure6', itemUnitsOfMeasurePayload.qtyPerUnitOfMeasure6),
|
||||
makeFieldPreview('CDU/Inner W (cm)', innerWIdx, 'width4', itemUnitsOfMeasurePayload.width4),
|
||||
makeFieldPreview('CDU/Inner L (cm)', innerLIdx, 'length4', itemUnitsOfMeasurePayload.length4),
|
||||
makeFieldPreview('CDU/Inner H (cm)', innerHIdx, 'height4', itemUnitsOfMeasurePayload.height4),
|
||||
makeFieldPreview('Outer W (cm)', outerWIdx, 'width6', itemUnitsOfMeasurePayload.width6),
|
||||
makeFieldPreview('Outer L (cm)', outerLIdx, 'length6', itemUnitsOfMeasurePayload.length6),
|
||||
makeFieldPreview('Outer H (cm)', outerHIdx, 'height6', itemUnitsOfMeasurePayload.height6),
|
||||
makeFieldPreview('Units Outer', unitsOuterIdx, 'qtyPerUnitOfMeasure', itemUnitsOfMeasurePayload.qtyPerUnitOfMeasure),
|
||||
makeFieldPreview('Outer W (cm)', outerWIdx, 'width', itemUnitsOfMeasurePayload.width),
|
||||
makeFieldPreview('Outer L (cm)', outerLIdx, 'length', itemUnitsOfMeasurePayload.length),
|
||||
makeFieldPreview('Outer H (cm)', outerHIdx, 'height', itemUnitsOfMeasurePayload.height),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -238,13 +229,21 @@ function getItemsSelect() {
|
||||
function getItemUnitsSelect() {
|
||||
return [
|
||||
'itemNo',
|
||||
'qtyPerUnitOfMeasure6',
|
||||
'width4',
|
||||
'length4',
|
||||
'height4',
|
||||
'width6',
|
||||
'length6',
|
||||
'height6',
|
||||
'code',
|
||||
'qtyPerUnitOfMeasure',
|
||||
'qtyRoundingPrecision',
|
||||
'length',
|
||||
'width',
|
||||
'height',
|
||||
'cubage',
|
||||
'weight',
|
||||
'layerPerPalet2CRZ',
|
||||
'outerPerLayer2CRZ',
|
||||
'barCodeCRZ',
|
||||
'layerPerPaletCRZ',
|
||||
'outerPerLayerCRZ',
|
||||
'netWeightCRZ',
|
||||
'innerTypeBCT',
|
||||
].join(',');
|
||||
}
|
||||
|
||||
@@ -270,7 +269,7 @@ export async function fetchBusinessCentralSnapshot(config, token, articleNo) {
|
||||
const { json: itemsJson, etag: itemsEtag } = await fetchJsonOrThrow(itemsUrl, token, 'BC GET items');
|
||||
const item = Array.isArray(itemsJson.value) && itemsJson.value.length > 0 ? itemsJson.value[0] : null;
|
||||
|
||||
const uomFilter = encodeURIComponent(`itemNo eq '${articleNo}'`);
|
||||
const uomFilter = encodeURIComponent(`itemNo eq '${articleNo}' and code eq '${config.itemUnitsCode || 'OUTER'}'`);
|
||||
const uomUrl = `${getItemUnitsOfMeasureUrl(config)}?$filter=${uomFilter}&$select=${getItemUnitsSelect()}`;
|
||||
const { json: uomJson, etag: uomEtag } = await fetchJsonOrThrow(uomUrl, token, 'BC GET itemUnitsOfMeasure');
|
||||
const itemUnitsOfMeasure = Array.isArray(uomJson.value) && uomJson.value.length > 0 ? uomJson.value[0] : null;
|
||||
@@ -388,13 +387,15 @@ function renderTemplate(template, context) {
|
||||
|
||||
const DECIMAL_FIELDS = new Set([
|
||||
'minimumOrderQuantity',
|
||||
'qtyPerUnitOfMeasure6',
|
||||
'width4',
|
||||
'length4',
|
||||
'height4',
|
||||
'width6',
|
||||
'length6',
|
||||
'height6',
|
||||
'qtyPerUnitOfMeasure',
|
||||
'length',
|
||||
'width',
|
||||
'height',
|
||||
'cubage',
|
||||
'weight',
|
||||
'layerPerPalet2CRZ',
|
||||
'outerPerLayer2CRZ',
|
||||
'netWeightCRZ',
|
||||
]);
|
||||
|
||||
const EMPTY_STRING_FIELDS = new Set([
|
||||
@@ -518,6 +519,7 @@ export async function applyBusinessCentralSync(config, token, headers, row, prev
|
||||
itemUnitsOfMeasureUrl: getItemUnitsOfMeasureUrl(config),
|
||||
articleNo: mapping.articleNo,
|
||||
itemNo: mapping.articleNo,
|
||||
itemUnitsCode: config.itemUnitsCode || 'OUTER',
|
||||
systemId: snapshot.item?.systemId || '',
|
||||
cpnpNo: mapping.itemsPayload.cpnpNo,
|
||||
itemsPayload: preview.items.desired,
|
||||
|
||||
@@ -497,7 +497,7 @@ export function MatrixView({ data, headers, rowStatuses }: MatrixViewProps) {
|
||||
<div className="rounded-lg border border-slate-700 bg-slate-950/60 p-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white">API `itemUnitsOfMeasure` preview</h3>
|
||||
<h3 className="text-sm font-semibold text-white">API `itemUnitsOfMeasure2` preview</h3>
|
||||
<p className="text-xs text-slate-400">SKU {bcMappingPreview.articleNo}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -81,9 +81,6 @@ export function buildBusinessCentralMappingPreview(headers: string[], row: Excel
|
||||
const cpnpIdx = findHeaderIndex(headers, ['cpnp']);
|
||||
|
||||
const unitsOuterIdx = findHeaderIndex(headers, ['units', 'outer']);
|
||||
const innerWIdx = findHeaderIndex(headers, ['inner', 'w']);
|
||||
const innerLIdx = findHeaderIndex(headers, ['inner', 'l']);
|
||||
const innerHIdx = findHeaderIndex(headers, ['inner', 'h']);
|
||||
const outerWIdx = findHeaderIndex(headers, ['outer', 'w']);
|
||||
const outerLIdx = findHeaderIndex(headers, ['outer', 'l']);
|
||||
const outerHIdx = findHeaderIndex(headers, ['outer', 'h']);
|
||||
@@ -104,13 +101,11 @@ export function buildBusinessCentralMappingPreview(headers: string[], row: Excel
|
||||
|
||||
const itemUnitsOfMeasurePayload = {
|
||||
itemNo: getValue(row, articleNoIdx),
|
||||
qtyPerUnitOfMeasure6: toBcDecimal(getValue(row, unitsOuterIdx)),
|
||||
width4: toBcDecimal(getValue(row, innerWIdx)),
|
||||
length4: toBcDecimal(getValue(row, innerLIdx)),
|
||||
height4: toBcDecimal(getValue(row, innerHIdx)),
|
||||
width6: toBcDecimal(getValue(row, outerWIdx)),
|
||||
length6: toBcDecimal(getValue(row, outerLIdx)),
|
||||
height6: toBcDecimal(getValue(row, outerHIdx)),
|
||||
code: 'OUTER',
|
||||
qtyPerUnitOfMeasure: toBcDecimal(getValue(row, unitsOuterIdx)),
|
||||
width: toBcDecimal(getValue(row, outerWIdx)),
|
||||
length: toBcDecimal(getValue(row, outerLIdx)),
|
||||
height: toBcDecimal(getValue(row, outerHIdx)),
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -130,13 +125,10 @@ export function buildBusinessCentralMappingPreview(headers: string[], row: Excel
|
||||
],
|
||||
itemUnitsFields: [
|
||||
makeFieldPreview('Article No.', articleNoIdx, 'itemNo', itemUnitsOfMeasurePayload.itemNo),
|
||||
makeFieldPreview('Units Outer', unitsOuterIdx, 'qtyPerUnitOfMeasure6', itemUnitsOfMeasurePayload.qtyPerUnitOfMeasure6),
|
||||
makeFieldPreview('CDU/Inner W (cm)', innerWIdx, 'width4', itemUnitsOfMeasurePayload.width4),
|
||||
makeFieldPreview('CDU/Inner L (cm)', innerLIdx, 'length4', itemUnitsOfMeasurePayload.length4),
|
||||
makeFieldPreview('CDU/Inner H (cm)', innerHIdx, 'height4', itemUnitsOfMeasurePayload.height4),
|
||||
makeFieldPreview('Outer W (cm)', outerWIdx, 'width6', itemUnitsOfMeasurePayload.width6),
|
||||
makeFieldPreview('Outer L (cm)', outerLIdx, 'length6', itemUnitsOfMeasurePayload.length6),
|
||||
makeFieldPreview('Outer H (cm)', outerHIdx, 'height6', itemUnitsOfMeasurePayload.height6),
|
||||
makeFieldPreview('Units Outer', unitsOuterIdx, 'qtyPerUnitOfMeasure', itemUnitsOfMeasurePayload.qtyPerUnitOfMeasure),
|
||||
makeFieldPreview('Outer W (cm)', outerWIdx, 'width', itemUnitsOfMeasurePayload.width),
|
||||
makeFieldPreview('Outer L (cm)', outerLIdx, 'length', itemUnitsOfMeasurePayload.length),
|
||||
makeFieldPreview('Outer H (cm)', outerHIdx, 'height', itemUnitsOfMeasurePayload.height),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user