Merge branch 'fix/marketing' into 'development'

[FIX/FE] Marketing - Sales Order Form

See merge request mbugroup/lti-web-client!374
This commit is contained in:
Rivaldi A N S
2026-04-07 10:44:49 +00:00
3 changed files with 120 additions and 94 deletions
@@ -195,7 +195,9 @@ const SalesOrderFormModal = ({
product.marketing_type?.value?.toLowerCase() === 'telur' product.marketing_type?.value?.toLowerCase() === 'telur'
? convertionUnitValue === 'PETI' ? convertionUnitValue === 'PETI'
? 'PETI' ? 'PETI'
: 'KG' // termasuk "QTY" dan "KG" : convertionUnitValue === 'QTY'
? 'QTY'
: 'KG'
: undefined; : undefined;
// Jika value dari data product ada week, kirim "AYAM_PULLET, jika tidak ada kirim "AYAM" // Jika value dari data product ada week, kirim "AYAM_PULLET, jika tidak ada kirim "AYAM"
@@ -61,14 +61,36 @@ const SalesOrderProductForm = ({
Number(initialValues.total_peti) Number(initialValues.total_peti)
: 0; : 0;
const initialPricePerConvertion = // const initialPricePerConvertion =
initialValues?.total_price && // initialValues?.total_price &&
initialValues?.total_peti && // initialValues?.total_peti &&
Number(initialValues.total_peti) !== 0 // Number(initialValues.total_peti) !== 0
? (Number(initialValues.total_price) - // ? (Number(initialValues.total_price) -
initialSisaBerat * Number(initialValues.unit_price || 0)) / // initialSisaBerat * Number(initialValues.unit_price || 0)) /
Number(initialValues.total_peti) // Number(initialValues.total_peti)
: 0; // : 0;
const initialPricePerConvertion = initialValues?.unit_price
? Number(initialValues?.unit_price)
: 0;
const isInitialTelurQty =
initialValues?.marketing_type?.value?.toLowerCase() === 'telur' &&
initialValues?.convertion_unit?.value?.toLowerCase() === 'qty';
const initialUnitPrice =
isInitialTelurQty &&
Number(initialValues?.total_price || 0) > 0 &&
Number(initialValues?.qty || 0) > 0
? Number(initialValues?.total_price) / Number(initialValues?.qty)
: initialValues?.unit_price || '';
const initialPricePerQty =
isInitialTelurQty &&
Number(initialValues?.total_price || 0) > 0 &&
Number(initialValues?.total_weight || 0) > 0
? Number(initialValues?.total_price) / Number(initialValues?.total_weight)
: (initialValues?.price_per_qty ?? null);
const initialPriceSisaBerat = const initialPriceSisaBerat =
initialValues?.total_price && initialValues?.total_peti initialValues?.total_price && initialValues?.total_peti
@@ -93,7 +115,7 @@ const SalesOrderProductForm = ({
product_warehouse: initialValues?.product_warehouse || null, product_warehouse: initialValues?.product_warehouse || null,
product_warehouse_data: initialValues?.product_warehouse_data || null, product_warehouse_data: initialValues?.product_warehouse_data || null,
product_warehouse_id: initialValues?.product_warehouse_id || undefined, product_warehouse_id: initialValues?.product_warehouse_id || undefined,
unit_price: initialValues?.unit_price || '', unit_price: initialUnitPrice,
total_weight: initialValues?.total_weight || '', total_weight: initialValues?.total_weight || '',
qty: initialValues?.qty || '', qty: initialValues?.qty || '',
avg_weight: initialValues?.avg_weight || '', avg_weight: initialValues?.avg_weight || '',
@@ -107,7 +129,7 @@ const SalesOrderProductForm = ({
convertion_unit: initialValues?.convertion_unit || null, convertion_unit: initialValues?.convertion_unit || null,
marketing_type: initialValues?.marketing_type || null, marketing_type: initialValues?.marketing_type || null,
total_peti: initialValues?.total_peti ?? null, total_peti: initialValues?.total_peti ?? null,
price_per_qty: initialValues?.price_per_qty ?? null, price_per_qty: initialPricePerQty,
sisa_berat: initialSisaBerat, sisa_berat: initialSisaBerat,
price_sisa_berat: initialPriceSisaBerat, price_sisa_berat: initialPriceSisaBerat,
week: initialValues?.week ?? null, week: initialValues?.week ?? null,
@@ -135,6 +157,11 @@ const SalesOrderProductForm = ({
); );
}, [selectedProductWarehouse, formik.values.marketing_type]); }, [selectedProductWarehouse, formik.values.marketing_type]);
console.log({
initialValues,
values: formik.values,
});
// ===== Options ===== // ===== Options =====
const { const {
options: warehouseOptions, options: warehouseOptions,
@@ -523,7 +550,7 @@ const SalesOrderProductForm = ({
<input <input
type='radio' type='radio'
checked={ checked={
formik.values.convertion_unit?.value === formik.values.convertion_unit?.value.toLowerCase() ===
option.value option.value
} }
onChange={() => null} onChange={() => null}
@@ -546,7 +573,9 @@ const SalesOrderProductForm = ({
} per ${formik.values.convertion_unit?.value}`} } per ${formik.values.convertion_unit?.value}`}
value={formik.values.weight_per_convertion ?? ''} value={formik.values.weight_per_convertion ?? ''}
onChange={(e) => { onChange={(e) => {
const value = Number(e.target.value); const value = Number(e.target.value)
? Number(e.target.value)
: '';
handleFieldChange('weight_per_convertion', value, () => handleFieldChange('weight_per_convertion', value, () =>
setCurrentInput(e.target.name) setCurrentInput(e.target.name)
); );
@@ -717,35 +746,12 @@ const SalesOrderProductForm = ({
/> />
)} )}
{/* Harga per butir untuk TELUR + QTY */}
{formik.values.marketing_type?.value.toLowerCase() === 'telur' &&
formik.values.convertion_unit?.value.toLowerCase() === 'qty' && (
<NumberInput
required
label='Harga / Butir (Rp)'
name='price_per_qty'
value={formik.values.price_per_qty ?? undefined}
onChange={(e) => {
const value = Number(e.target.value);
handleFieldChange('price_per_qty', value, () =>
setCurrentInput('price_per_qty')
);
}}
isError={
formik.touched.price_per_qty &&
Boolean(formik.errors.price_per_qty)
}
errorMessage={formik.errors.price_per_qty}
placeholder='Masukan Harga per Butir'
/>
)}
{/* Harga Satuan per Uom Produk Warehouse */} {/* Harga Satuan per Uom Produk Warehouse */}
{formik.values.convertion_unit?.value.toLowerCase() !== 'peti' && {formik.values.convertion_unit?.value.toLowerCase() !== 'peti' &&
formik.values.convertion_unit?.value.toLowerCase() !== 'kg' && ( formik.values.convertion_unit?.value.toLowerCase() !== 'kg' && (
<NumberInput <NumberInput
required required
label={`Harga / ${formik.values.convertion_unit?.label !== 'qty' ? 'Kg' : (selectedProductWarehouse?.product?.uom?.name ?? 'Produk')} (Rp)`} label={`Harga / ${formik.values.convertion_unit?.label.toLowerCase() !== 'qty' ? 'Kg' : 'Butir'} (Rp)`}
name='unit_price' name='unit_price'
value={formik.values.unit_price} value={formik.values.unit_price}
onChange={(e) => { onChange={(e) => {
@@ -762,6 +768,29 @@ const SalesOrderProductForm = ({
/> />
)} )}
{/* Harga per kg untuk TELUR + QTY */}
{formik.values.marketing_type?.value.toLowerCase() === 'telur' &&
formik.values.convertion_unit?.value.toLowerCase() === 'qty' && (
<NumberInput
required
label='Harga / Kg (Rp)'
name='price_per_qty'
value={formik.values.price_per_qty ?? undefined}
onChange={(e) => {
const value = Number(e.target.value);
handleFieldChange('price_per_qty', value, () =>
setCurrentInput('price_per_qty')
);
}}
isError={
formik.touched.price_per_qty &&
Boolean(formik.errors.price_per_qty)
}
errorMessage={formik.errors.price_per_qty}
placeholder='Masukan Harga per Kg'
/>
)}
{/* Sisa kg diluar peti */} {/* Sisa kg diluar peti */}
{formik.values.convertion_unit?.value.toLowerCase() === 'peti' && ( {formik.values.convertion_unit?.value.toLowerCase() === 'peti' && (
<div className='flex flex-col'> <div className='flex flex-col'>
+52 -57
View File
@@ -76,13 +76,13 @@ export const calculateTrading = (
case 'unit_price': case 'unit_price':
case 'qty': { case 'qty': {
if (unitPrice > 0 && qty > 0) { if (unitPrice > 0 && qty > 0) {
setFieldValue('total_price', roundPrice(unitPrice * qty)); setFieldValue('total_price', unitPrice * qty);
} }
break; break;
} }
case 'total_price': { case 'total_price': {
if (totalPrice > 0 && qty > 0) { if (totalPrice > 0 && qty > 0) {
setFieldValue('unit_price', roundPrice(totalPrice / qty)); setFieldValue('unit_price', totalPrice / qty);
} }
break; break;
} }
@@ -112,7 +112,7 @@ export const calculateAyamPullet = (
case 'qty': { case 'qty': {
// total_price = unit_price × week × qty // total_price = unit_price × week × qty
if (unitPrice > 0 && week > 0 && qty > 0) { if (unitPrice > 0 && week > 0 && qty > 0) {
setFieldValue('total_price', roundPrice(unitPrice * week * qty)); setFieldValue('total_price', unitPrice * week * qty);
} }
// total_weight = avg_weight × qty // total_weight = avg_weight × qty
if (avgWeight > 0 && qty > 0) { if (avgWeight > 0 && qty > 0) {
@@ -135,7 +135,7 @@ export const calculateAyamPullet = (
case 'total_price': { case 'total_price': {
// Reverse: unit_price = total_price / (week × qty) // Reverse: unit_price = total_price / (week × qty)
if (totalPrice > 0 && week > 0 && qty > 0) { if (totalPrice > 0 && week > 0 && qty > 0) {
setFieldValue('unit_price', roundPrice(totalPrice / (week * qty))); setFieldValue('unit_price', totalPrice / (week * qty));
} }
break; break;
} }
@@ -164,7 +164,7 @@ export const calculateAyam = (field: string, ctx: CalculationContext): void => {
setFieldValue('total_weight', tw); setFieldValue('total_weight', tw);
// total_price = total_weight × unit_price // total_price = total_weight × unit_price
if (unitPrice > 0) { if (unitPrice > 0) {
setFieldValue('total_price', roundPrice(tw * unitPrice)); setFieldValue('total_price', tw * unitPrice);
} }
} }
break; break;
@@ -176,21 +176,21 @@ export const calculateAyam = (field: string, ctx: CalculationContext): void => {
} }
// total_price = total_weight × unit_price // total_price = total_weight × unit_price
if (unitPrice > 0 && totalWeight > 0) { if (unitPrice > 0 && totalWeight > 0) {
setFieldValue('total_price', roundPrice(totalWeight * unitPrice)); setFieldValue('total_price', totalWeight * unitPrice);
} }
break; break;
} }
case 'unit_price': { case 'unit_price': {
// total_price = total_weight × unit_price // total_price = total_weight × unit_price
if (unitPrice > 0 && totalWeight > 0) { if (unitPrice > 0 && totalWeight > 0) {
setFieldValue('total_price', roundPrice(totalWeight * unitPrice)); setFieldValue('total_price', totalWeight * unitPrice);
} }
break; break;
} }
case 'total_price': { case 'total_price': {
// unit_price = total_price / total_weight // unit_price = total_price / total_weight
if (totalPrice > 0 && totalWeight > 0) { if (totalPrice > 0 && totalWeight > 0) {
setFieldValue('unit_price', roundPrice(totalPrice / totalWeight)); setFieldValue('unit_price', totalPrice / totalWeight);
} }
break; break;
} }
@@ -223,7 +223,8 @@ export const calculateTelurPeti = (
// Helper untuk menghitung dan set unit_price = total_price / total_weight // Helper untuk menghitung dan set unit_price = total_price / total_weight
const updateUnitPrice = (tp: number, tw: number) => { const updateUnitPrice = (tp: number, tw: number) => {
if (tw > 0 && tp > 0) { if (tw > 0 && tp > 0) {
setFieldValue('unit_price', roundPrice(tp / tw)); const unitPrice = tp / tw;
setFieldValue('unit_price', unitPrice);
} }
}; };
@@ -232,10 +233,12 @@ export const calculateTelurPeti = (
// Recalculate total_price = (price_per_convertion × total_peti) + price_sisa_berat // Recalculate total_price = (price_per_convertion × total_peti) + price_sisa_berat
if (pricePerConvertion > 0 && totalPeti > 0) { if (pricePerConvertion > 0 && totalPeti > 0) {
const totalPrice = pricePerConvertion * totalPeti + priceSisaBerat; const totalPrice = pricePerConvertion * totalPeti + priceSisaBerat;
setFieldValue('total_price', roundPrice(totalPrice)); setFieldValue('total_price', totalPrice);
// Recalculate unit_price = total_price / total_weight // Recalculate unit_price = total_price / total_weight
// TODO: consider sisa berat later
const totalWeight = weightPerConvertion * totalPeti + sisaBerat; const totalWeight = weightPerConvertion * totalPeti + sisaBerat;
updateUnitPrice(totalPrice, totalWeight); updateUnitPrice(totalPrice, totalPeti);
} }
break; break;
} }
@@ -253,9 +256,9 @@ export const calculateTelurPeti = (
// Recalculate total_price = (price_per_convertion × total_peti) + price_sisa_berat // Recalculate total_price = (price_per_convertion × total_peti) + price_sisa_berat
if (pricePerConvertion > 0 && totalPeti > 0) { if (pricePerConvertion > 0 && totalPeti > 0) {
const totalPrice = pricePerConvertion * totalPeti + priceSisaBerat; const totalPrice = pricePerConvertion * totalPeti + priceSisaBerat;
setFieldValue('total_price', roundPrice(totalPrice)); setFieldValue('total_price', totalPrice);
// Recalculate unit_price = total_price / total_weight // Recalculate unit_price = total_price / total_peti
updateUnitPrice(totalPrice, totalWeight); updateUnitPrice(totalPrice, totalPeti);
} }
break; break;
} }
@@ -263,7 +266,7 @@ export const calculateTelurPeti = (
// Recalculate total_price // Recalculate total_price
if (pricePerConvertion > 0 && totalPeti > 0) { if (pricePerConvertion > 0 && totalPeti > 0) {
const totalPrice = pricePerConvertion * totalPeti + priceSisaBerat; const totalPrice = pricePerConvertion * totalPeti + priceSisaBerat;
setFieldValue('total_price', roundPrice(totalPrice)); setFieldValue('total_price', totalPrice);
// Recalculate unit_price = total_price / total_weight // Recalculate unit_price = total_price / total_weight
const totalWeight = weightPerConvertion * totalPeti + sisaBerat; const totalWeight = weightPerConvertion * totalPeti + sisaBerat;
updateUnitPrice(totalPrice, totalWeight); updateUnitPrice(totalPrice, totalWeight);
@@ -306,7 +309,7 @@ export const calculateTelurPeti = (
if (totalPeti > 0 && totalPrice > priceSisaBerat) { if (totalPeti > 0 && totalPrice > priceSisaBerat) {
setFieldValue( setFieldValue(
'price_per_convertion', 'price_per_convertion',
roundPrice((totalPrice - priceSisaBerat) / totalPeti) (totalPrice - priceSisaBerat) / totalPeti
); );
} }
// Update unit_price = total_price / total_weight // Update unit_price = total_price / total_weight
@@ -341,10 +344,7 @@ export const calculateTelurKg = (
} }
// total_price = total_weight × unit_price // total_price = total_weight × unit_price
if (pricePerConvertion > 0 && totalWeight > 0) { if (pricePerConvertion > 0 && totalWeight > 0) {
setFieldValue( setFieldValue('total_price', totalWeight * pricePerConvertion);
'total_price',
roundPrice(totalWeight * pricePerConvertion)
);
setFieldValue('unit_price', pricePerConvertion); setFieldValue('unit_price', pricePerConvertion);
} }
break; break;
@@ -352,10 +352,7 @@ export const calculateTelurKg = (
case 'price_per_convertion': { case 'price_per_convertion': {
// total_price = total_weight × price_per_convertion // total_price = total_weight × price_per_convertion
if (pricePerConvertion > 0 && totalWeight > 0) { if (pricePerConvertion > 0 && totalWeight > 0) {
setFieldValue( setFieldValue('total_price', totalWeight * pricePerConvertion);
'total_price',
roundPrice(totalWeight * pricePerConvertion)
);
setFieldValue('unit_price', pricePerConvertion); setFieldValue('unit_price', pricePerConvertion);
} }
break; break;
@@ -363,11 +360,8 @@ export const calculateTelurKg = (
case 'total_price': { case 'total_price': {
// unit_price = total_price / total_weight // unit_price = total_price / total_weight
if (totalPrice > 0 && totalWeight > 0) { if (totalPrice > 0 && totalWeight > 0) {
setFieldValue('unit_price', roundPrice(totalPrice / totalWeight)); setFieldValue('unit_price', totalPrice / totalWeight);
setFieldValue( setFieldValue('price_per_convertion', totalPrice / totalWeight);
'price_per_convertion',
roundPrice(totalPrice / totalWeight)
);
} }
break; break;
} }
@@ -376,13 +370,11 @@ export const calculateTelurKg = (
/** /**
* TELUR + QTY Workaround: * TELUR + QTY Workaround:
* - User inputs: qty, avg_weight, price_per_qty (harga per butir) * - User inputs: qty, avg_weight, unit_price (harga per butir)
* - FE calculates: * - FE calculates:
* - total_weight = avg_weight × qty * - total_weight = avg_weight × qty
* - total_price = qty × price_per_qty * - total_price = qty × unit_price
* - unit_price = total_price / total_weight (normalisasi untuk BE) * - price_per_qty = total_price / total_weight (harga per kg)
* - Kirim convertion_unit: "KG" karena BE tidak support "QTY"
* - BE akan hitung: total_price = total_weight × unit_price (hasil sama)
*/ */
export const calculateTelurQty = ( export const calculateTelurQty = (
field: string, field: string,
@@ -403,13 +395,13 @@ export const calculateTelurQty = (
if (avgWeight > 0 && qty > 0) { if (avgWeight > 0 && qty > 0) {
const tw = roundWeight(avgWeight * qty); const tw = roundWeight(avgWeight * qty);
setFieldValue('total_weight', tw); setFieldValue('total_weight', tw);
// total_price = qty × price_per_qty // total_price = qty × unit_price
if (pricePerQty > 0) { if (unitPrice > 0) {
const tp = roundPrice(qty * pricePerQty); const tp = qty * unitPrice;
setFieldValue('total_price', tp); setFieldValue('total_price', tp);
// unit_price = total_price / total_weight (untuk BE) // price_per_qty = total_price / total_weight
if (tw > 0) { if (tw > 0) {
setFieldValue('unit_price', roundPrice(tp / tw)); setFieldValue('price_per_qty', tp / tw);
} }
} }
} }
@@ -419,44 +411,47 @@ export const calculateTelurQty = (
// avg_weight = total_weight / qty // avg_weight = total_weight / qty
if (totalWeight > 0 && qty > 0) { if (totalWeight > 0 && qty > 0) {
setFieldValue('avg_weight', preciseWeight(totalWeight / qty)); setFieldValue('avg_weight', preciseWeight(totalWeight / qty));
// Recalculate total_price jika ada unit_price // Recalculate total_price jika ada harga per butir
if (unitPrice > 0) { if (unitPrice > 0) {
setFieldValue('total_price', roundPrice(totalWeight * unitPrice)); setFieldValue('total_price', qty * unitPrice);
} }
} }
break; break;
} }
case 'price_per_qty': { case 'price_per_qty': {
// total_price = qty × price_per_qty // total_price = total_weight × price_per_qty
if (pricePerQty > 0 && qty > 0) { if (pricePerQty > 0 && totalWeight > 0) {
const tp = roundPrice(qty * pricePerQty); const tp = totalWeight * pricePerQty;
setFieldValue('total_price', tp); setFieldValue('total_price', tp);
// unit_price = total_price / total_weight (untuk BE) // unit_price = total_price / qty
if (totalWeight > 0) { if (qty > 0) {
setFieldValue('unit_price', roundPrice(tp / totalWeight)); setFieldValue('unit_price', tp / qty);
} }
} }
break; break;
} }
case 'total_price': { case 'total_price': {
// price_per_qty = total_price / qty // unit_price = total_price / qty
if (totalPrice > 0 && qty > 0) { if (totalPrice > 0 && qty > 0) {
setFieldValue('price_per_qty', roundPrice(totalPrice / qty)); setFieldValue('unit_price', totalPrice / qty);
// unit_price = total_price / total_weight (untuk BE) // price_per_qty = total_price / total_weight
if (totalWeight > 0) { if (totalWeight > 0) {
setFieldValue('unit_price', roundPrice(totalPrice / totalWeight)); setFieldValue('price_per_qty', totalPrice / totalWeight);
} }
} }
break; break;
} }
case 'unit_price': { case 'unit_price': {
// total_price = total_weight × unit_price // total_price = qty × unit_price
if (unitPrice > 0 && totalWeight > 0) { const newTotalPrice = qty * unitPrice;
setFieldValue('total_price', roundPrice(totalWeight * unitPrice));
if (unitPrice > 0 && qty > 0) {
setFieldValue('total_price', newTotalPrice);
} }
// price_per_qty = total_price / qty
if (totalPrice > 0 && qty > 0) { // price_per_qty = total_price / total_weight
setFieldValue('price_per_qty', roundPrice(totalPrice / qty)); if (newTotalPrice > 0 && totalWeight > 0) {
setFieldValue('price_per_qty', newTotalPrice / totalWeight);
} }
break; break;
} }