@zauru-sdk/utils 6.5.0 → 6.6.1

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/esm/index.js CHANGED
@@ -19,6 +19,7 @@ export * from "./zauru/purchase-orders.utils.js";
19
19
  export * from "./zauru/shipments.utils.js";
20
20
  export * from "./zauru/specialItem.utils.js";
21
21
  export * from "./zauru/priceAdjustmentRules.utils.js";
22
+ export * from "./zauru/weeklyItemPrice.utils.js";
22
23
  export * from "./zauru/templates.utils.js";
23
24
  export * from "./zauru/tiposMuestra.utils.js";
24
25
  export * from "./zauru/webapp-tables.utils.js";
@@ -79,8 +79,8 @@ const formatRuleEffect = (step) => {
79
79
  }
80
80
  return `${formatSignedAmount(step.appliedAmount)} (${step.ruleName})`;
81
81
  };
82
- export const formatPriceAdjustmentDescription = (result) => {
83
- const base = `${formatMoney(result.basePrice)} (base)`;
82
+ export const formatPriceAdjustmentDescription = (result, baseLabel = "base") => {
83
+ const base = `${formatMoney(result.basePrice)} (${baseLabel})`;
84
84
  if (result.steps.length === 0) {
85
85
  return base;
86
86
  }
@@ -0,0 +1,213 @@
1
+ import { handlePossibleAxiosErrors } from "@zauru-sdk/common";
2
+ import { getPayee, getPayees } from "@zauru-sdk/services";
3
+ import { getCostosBitacora } from "./costos-items.utils.js";
4
+ import { applyPriceAdjustmentRules, filterActivePriceAdjustmentRules, formatPriceAdjustmentDescription, getPriceAdjustmentRules, } from "./priceAdjustmentRules.utils.js";
5
+ import { getSpecialItems } from "./specialItem.utils.js";
6
+ export const MASSIVE_VEGETABLE_COST_ACCION = "Costos masivamente";
7
+ const FALLBACK_UNIT_COST = 1;
8
+ const isSpecialItemRow = (item) => typeof item.id === "number" &&
9
+ Boolean(item.data);
10
+ const isWeekday = (value) => value === 0 ||
11
+ value === 1 ||
12
+ value === 2 ||
13
+ value === 3 ||
14
+ value === 4 ||
15
+ value === 5 ||
16
+ value === 6;
17
+ export const parseWeeklyCostDate = (value) => {
18
+ const trimmed = String(value ?? "").trim();
19
+ if (!trimmed) {
20
+ return null;
21
+ }
22
+ const ymd = /^(\d{4})[-/](\d{2})[-/](\d{2})/.exec(trimmed);
23
+ if (ymd) {
24
+ return new Date(Number(ymd[1]), Number(ymd[2]) - 1, Number(ymd[3]));
25
+ }
26
+ const dmy = /^(\d{2})[-/](\d{2})[-/](\d{4})/.exec(trimmed);
27
+ if (dmy) {
28
+ return new Date(Number(dmy[3]), Number(dmy[2]) - 1, Number(dmy[1]));
29
+ }
30
+ const parsed = new Date(trimmed);
31
+ if (Number.isNaN(parsed.getTime())) {
32
+ return null;
33
+ }
34
+ return new Date(parsed.getFullYear(), parsed.getMonth(), parsed.getDate());
35
+ };
36
+ const formatDateYYYYSlashMMSlashDD = (date) => {
37
+ const year = date.getFullYear();
38
+ const month = String(date.getMonth() + 1).padStart(2, "0");
39
+ const day = String(date.getDate()).padStart(2, "0");
40
+ return `${year}/${month}/${day}`;
41
+ };
42
+ export const getMondayOfWeeklyCostDate = (date) => {
43
+ const parsed = parseWeeklyCostDate(date);
44
+ if (!parsed) {
45
+ return null;
46
+ }
47
+ const weekday = parsed.getDay();
48
+ const daysFromMonday = weekday === 0 ? 6 : weekday - 1;
49
+ const monday = new Date(parsed);
50
+ monday.setDate(parsed.getDate() - daysFromMonday);
51
+ return formatDateYYYYSlashMMSlashDD(monday);
52
+ };
53
+ export const getWeeklyCostPeriod = (date) => {
54
+ const parsed = parseWeeklyCostDate(date);
55
+ const weekday = parsed?.getDay();
56
+ if (!parsed || weekday === undefined || !isWeekday(weekday)) {
57
+ return "lunMar";
58
+ }
59
+ switch (weekday) {
60
+ case 1:
61
+ case 2:
62
+ return "lunMar";
63
+ case 3:
64
+ case 4:
65
+ return "mieJue";
66
+ case 5:
67
+ case 6:
68
+ case 0:
69
+ return "vieSabDom";
70
+ default: {
71
+ const _exhaustive = weekday;
72
+ return _exhaustive;
73
+ }
74
+ }
75
+ };
76
+ export const getWeeklyCostPeriodPrice = (costo, period) => {
77
+ if (!costo) {
78
+ return null;
79
+ }
80
+ const value = Number(costo[period]);
81
+ if (!Number.isFinite(value) || value <= 0) {
82
+ return null;
83
+ }
84
+ return value;
85
+ };
86
+ export const getPriceByDate = (date, _fechas, costo) => getWeeklyCostPeriodPrice(costo, getWeeklyCostPeriod(date)) ?? FALLBACK_UNIT_COST;
87
+ export const filterActiveSpecialItems = (specialItems) => (specialItems ?? [])
88
+ .filter(isSpecialItemRow)
89
+ .filter((row) => !row.data?.fechaEliminacion)
90
+ .sort((a, b) => a.id - b.id);
91
+ export const matchSpecialItemForWeeklyPrice = (specialItems, params) => filterActiveSpecialItems(specialItems).find((specialItem) => specialItem.data.item === params.itemId &&
92
+ specialItem.data.region === params.region &&
93
+ specialItem.data.tipo === params.tipo);
94
+ export const pickLatestMassiveCostBitacora = (rows, date) => {
95
+ const masivas = (rows ?? [])
96
+ .filter((row) => row.data?.accion === MASSIVE_VEGETABLE_COST_ACCION)
97
+ .sort((a, b) => b.id - a.id);
98
+ const monday = date ? getMondayOfWeeklyCostDate(date) : null;
99
+ if (monday) {
100
+ const matchingWeek = masivas.find((row) => row.data?.fechas?.lunes === monday);
101
+ if (matchingWeek) {
102
+ return matchingWeek;
103
+ }
104
+ }
105
+ return masivas[0];
106
+ };
107
+ const sourceLabel = (source) => {
108
+ if (source === "especial") {
109
+ return "especial";
110
+ }
111
+ if (source === "fallback") {
112
+ return "sin matriz";
113
+ }
114
+ return "base";
115
+ };
116
+ export const calculateItemPriceFromWeeklyMatrix = (input) => {
117
+ const period = getWeeklyCostPeriod(input.date);
118
+ const matrix = input.matrix;
119
+ const matchedSpecial = matchSpecialItemForWeeklyPrice(input.specialItems, {
120
+ itemId: input.itemId,
121
+ region: input.region,
122
+ tipo: input.tipo,
123
+ });
124
+ let source = "fallback";
125
+ let basePrice = FALLBACK_UNIT_COST;
126
+ let specialItemId;
127
+ if (matchedSpecial) {
128
+ const specialPrice = getWeeklyCostPeriodPrice(matrix?.costosEspeciales?.find((costo) => costo.specialItemId === matchedSpecial.id), period);
129
+ if (specialPrice != null) {
130
+ source = "especial";
131
+ basePrice = specialPrice;
132
+ specialItemId = matchedSpecial.id;
133
+ }
134
+ }
135
+ if (source === "fallback") {
136
+ const generalPrice = getWeeklyCostPeriodPrice(matrix?.costos?.find((costo) => costo.item === input.itemId), period);
137
+ if (generalPrice != null) {
138
+ source = "general";
139
+ basePrice = generalPrice;
140
+ }
141
+ }
142
+ const adjusted = applyPriceAdjustmentRules(basePrice, input.rules ?? [], {
143
+ itemId: input.itemId,
144
+ tipo: input.tipo,
145
+ providerCategoryId: input.providerCategoryId,
146
+ });
147
+ return {
148
+ ...adjusted,
149
+ description: formatPriceAdjustmentDescription(adjusted, sourceLabel(source)),
150
+ source,
151
+ period,
152
+ specialItemId,
153
+ };
154
+ };
155
+ export const loadLatestWeeklyCostMatrix = (headers, session, date) => {
156
+ return handlePossibleAxiosErrors(async () => {
157
+ const bitacoraResponse = await getCostosBitacora(headers, session);
158
+ if (bitacoraResponse.error) {
159
+ throw new Error(`Error al intentar obtener la bitácora de costos de verduras: ${bitacoraResponse.userMsg ?? ""}`);
160
+ }
161
+ const bitacoraRow = pickLatestMassiveCostBitacora(bitacoraResponse.data ?? [], date);
162
+ if (!bitacoraRow?.data) {
163
+ return null;
164
+ }
165
+ return {
166
+ costos: bitacoraRow.data.costos ?? [],
167
+ costosEspeciales: bitacoraRow.data.costosEspeciales ?? [],
168
+ fechas: bitacoraRow.data.fechas,
169
+ };
170
+ });
171
+ };
172
+ export const resolveItemPriceFromLatestWeeklyMatrix = (headers, session, params) => {
173
+ return handlePossibleAxiosErrors(async () => {
174
+ const [matrixResponse, specialItemsResponse, rulesResponse] = await Promise.all([
175
+ loadLatestWeeklyCostMatrix(headers, session, params.date),
176
+ getSpecialItems(headers, session),
177
+ getPriceAdjustmentRules(headers, session),
178
+ ]);
179
+ if (matrixResponse.error) {
180
+ throw new Error(`Error al cargar la última matriz de costos: ${matrixResponse.userMsg ?? ""}`);
181
+ }
182
+ if (specialItemsResponse.error) {
183
+ throw new Error(`Error al intentar obtener los precios especiales de verduras: ${specialItemsResponse.userMsg ?? ""}`);
184
+ }
185
+ if (rulesResponse.error) {
186
+ throw new Error(`Error al obtener las reglas de ajuste de precio: ${rulesResponse.userMsg ?? ""}`);
187
+ }
188
+ let providerCategoryId;
189
+ if (params.payeeId != null) {
190
+ const payeeResponse = await getPayee(session, params.payeeId);
191
+ if (!payeeResponse.error && payeeResponse.data) {
192
+ providerCategoryId = payeeResponse.data.payee_category_id;
193
+ }
194
+ else {
195
+ const payeesResponse = await getPayees(session);
196
+ if (payeesResponse.error || !payeesResponse.data) {
197
+ throw new Error(`Error al obtener el proveedor para aplicar las reglas de ajuste: ${payeeResponse.userMsg ?? payeesResponse.userMsg ?? ""}`);
198
+ }
199
+ providerCategoryId = payeesResponse.data.find((payee) => payee.id === params.payeeId)?.payee_category_id;
200
+ }
201
+ }
202
+ return calculateItemPriceFromWeeklyMatrix({
203
+ itemId: params.itemId,
204
+ date: params.date,
205
+ region: params.region,
206
+ tipo: params.tipo,
207
+ providerCategoryId,
208
+ matrix: matrixResponse.data,
209
+ specialItems: specialItemsResponse.data ?? [],
210
+ rules: filterActivePriceAdjustmentRules(rulesResponse.data),
211
+ });
212
+ });
213
+ };
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ export * from "./zauru/purchase-orders.utils.js";
19
19
  export * from "./zauru/shipments.utils.js";
20
20
  export * from "./zauru/specialItem.utils.js";
21
21
  export * from "./zauru/priceAdjustmentRules.utils.js";
22
+ export * from "./zauru/weeklyItemPrice.utils.js";
22
23
  export * from "./zauru/templates.utils.js";
23
24
  export * from "./zauru/tiposMuestra.utils.js";
24
25
  export * from "./zauru/webapp-tables.utils.js";
@@ -6,5 +6,5 @@ export declare const getPriceAdjustmentRules: (headers: any, session: Session) =
6
6
  export declare const createPriceAdjustmentRule: (headers: any, session: Session, body: PriceAdjustmentRule) => Promise<AxiosUtilsResponse<WebAppTableUpdateResponse>>;
7
7
  export declare const updatePriceAdjustmentRule: (headers: any, session: Session, id: string, body: Partial<PriceAdjustmentRule>) => Promise<AxiosUtilsResponse<WebAppTableUpdateResponse>>;
8
8
  export declare const priceAdjustmentRuleMatches: (rule: PriceAdjustmentRule, ctx: PriceAdjustmentContext) => boolean;
9
- export declare const formatPriceAdjustmentDescription: (result: Pick<PriceAdjustmentResult, "basePrice" | "finalPrice" | "steps">) => string;
9
+ export declare const formatPriceAdjustmentDescription: (result: Pick<PriceAdjustmentResult, "basePrice" | "finalPrice" | "steps">, baseLabel?: string) => string;
10
10
  export declare const applyPriceAdjustmentRules: (basePrice: number, rules: Array<PriceAdjustmentRule | WebAppRowGraphQL<PriceAdjustmentRule>>, ctx: PriceAdjustmentContext) => PriceAdjustmentResult;
@@ -0,0 +1,24 @@
1
+ import type { Session } from "@remix-run/node";
2
+ import { AxiosUtilsResponse, BitacoraCostosItems, CalculateItemPriceFromWeeklyMatrixInput, CalculateItemPriceFromWeeklyMatrixResult, CostoSemanal, CostoSemanalSpecialItem, SpecialItem, WebAppRowGraphQL, WeeklyCostMatrix, WeeklyCostPeriod } from "@zauru-sdk/types";
3
+ export declare const MASSIVE_VEGETABLE_COST_ACCION = "Costos masivamente";
4
+ export declare const parseWeeklyCostDate: (value: string) => Date | null;
5
+ export declare const getMondayOfWeeklyCostDate: (date: string) => string | null;
6
+ export declare const getWeeklyCostPeriod: (date: string) => WeeklyCostPeriod;
7
+ export declare const getWeeklyCostPeriodPrice: (costo: Pick<CostoSemanal, WeeklyCostPeriod> | undefined, period: WeeklyCostPeriod) => number | null;
8
+ export declare const getPriceByDate: (date: string, _fechas: WeeklyCostMatrix["fechas"] | undefined, costo?: CostoSemanal | CostoSemanalSpecialItem) => number;
9
+ export declare const filterActiveSpecialItems: (specialItems?: Array<SpecialItem | WebAppRowGraphQL<SpecialItem>>) => WebAppRowGraphQL<SpecialItem>[];
10
+ export declare const matchSpecialItemForWeeklyPrice: (specialItems: Array<SpecialItem | WebAppRowGraphQL<SpecialItem>> | undefined, params: {
11
+ itemId: number;
12
+ region?: string;
13
+ tipo?: string;
14
+ }) => WebAppRowGraphQL<SpecialItem> | undefined;
15
+ export declare const pickLatestMassiveCostBitacora: (rows: WebAppRowGraphQL<BitacoraCostosItems>[] | undefined, date?: string) => WebAppRowGraphQL<BitacoraCostosItems> | undefined;
16
+ export declare const calculateItemPriceFromWeeklyMatrix: (input: CalculateItemPriceFromWeeklyMatrixInput) => CalculateItemPriceFromWeeklyMatrixResult;
17
+ export declare const loadLatestWeeklyCostMatrix: (headers: any, session: Session, date?: string) => Promise<AxiosUtilsResponse<WeeklyCostMatrix | null>>;
18
+ export declare const resolveItemPriceFromLatestWeeklyMatrix: (headers: any, session: Session, params: {
19
+ itemId: number;
20
+ date: string;
21
+ region?: string;
22
+ tipo?: string;
23
+ payeeId?: number;
24
+ }) => Promise<AxiosUtilsResponse<CalculateItemPriceFromWeeklyMatrixResult>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zauru-sdk/utils",
3
- "version": "6.5.0",
3
+ "version": "6.6.1",
4
4
  "description": "Utilidades, parseo de request y demás para desarrollo de webapps de Zauru",
5
5
  "main": "./dist/esm/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -25,12 +25,12 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@remix-run/node": "^2.8.1",
28
- "@zauru-sdk/common": "^6.3.3",
28
+ "@zauru-sdk/common": "^6.3.4",
29
29
  "@zauru-sdk/config": "^6.0.0",
30
30
  "@zauru-sdk/graphql": "^6.5.0",
31
- "@zauru-sdk/services": "^6.7.1",
32
- "@zauru-sdk/types": "^6.11.0",
31
+ "@zauru-sdk/services": "^6.7.3",
32
+ "@zauru-sdk/types": "^6.12.0",
33
33
  "moment": "^2.30.1"
34
34
  },
35
- "gitHead": "3b01e2440af4265aa61b77aba1e7dd33abb2e4fa"
35
+ "gitHead": "f05db6e411cd5af8104570563e94d800e7b390e3"
36
36
  }