mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
Merge branch 'fix/marketing-delivery-order' into 'development'
[FIX/FE] Marketing Delivery Order See merge request mbugroup/lti-web-client!380
This commit is contained in:
@@ -368,7 +368,9 @@ const DeliveryOrderFormModal = ({}: { initialValues?: Marketing }) => {
|
||||
const currentProducts = deliveryOrderValues?.find(
|
||||
(product) => product.id == id
|
||||
);
|
||||
setSelectedDeliveryProduct(values ?? currentProducts ?? null);
|
||||
|
||||
setSelectedDeliveryProduct(currentProducts ?? values ?? null);
|
||||
|
||||
if (id) {
|
||||
setStep(2);
|
||||
}
|
||||
|
||||
@@ -144,15 +144,15 @@ export const DeliveryProductToFieldValues = (
|
||||
delivery: BaseDeliveryOrder
|
||||
): DeliveryOrderProductFormValues[] => {
|
||||
const data = delivery.deliveries.map((item) => {
|
||||
const soId = salesOrders.find(
|
||||
const salesOrder = salesOrders.find(
|
||||
(so) => so.product_warehouse.id === item.product_warehouse.id
|
||||
)?.id;
|
||||
);
|
||||
const warehouseOption = {
|
||||
value: item.product_warehouse.warehouse.id,
|
||||
label: item.product_warehouse.warehouse.name,
|
||||
};
|
||||
return {
|
||||
id: soId,
|
||||
id: salesOrder?.id,
|
||||
unit_price: item.unit_price,
|
||||
total_weight: item.total_weight,
|
||||
qty: item.qty,
|
||||
@@ -161,9 +161,21 @@ export const DeliveryProductToFieldValues = (
|
||||
vehicle_number: item.vehicle_number,
|
||||
delivery_date: formatDate(delivery.delivery_date, 'yyyy-MM-DD'),
|
||||
do_number: delivery.do_number,
|
||||
marketing_product_id: soId,
|
||||
marketing_product_id: salesOrder?.id,
|
||||
marketing_type: salesOrder?.marketing_type
|
||||
? {
|
||||
value: salesOrder?.marketing_type,
|
||||
label: formatTitleCase(salesOrder?.marketing_type),
|
||||
}
|
||||
: null,
|
||||
convertion_unit: salesOrder?.convertion_unit
|
||||
? {
|
||||
value: salesOrder?.convertion_unit.toLowerCase(),
|
||||
label: formatTitleCase(salesOrder?.convertion_unit),
|
||||
}
|
||||
: null,
|
||||
marketing_product: {
|
||||
id: soId,
|
||||
id: salesOrder?.id,
|
||||
vehicle_number: item.vehicle_number,
|
||||
warehouse_id: item.product_warehouse.warehouse.id,
|
||||
warehouse: warehouseOption,
|
||||
@@ -183,6 +195,7 @@ export const DeliveryProductToFieldValues = (
|
||||
},
|
||||
} as DeliveryOrderProductFormValues;
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
export const mergeSOwithDO = (
|
||||
@@ -194,6 +207,19 @@ export const mergeSOwithDO = (
|
||||
const delivery = deliveryOrders.find(
|
||||
(d) => d?.marketing_product_id === so.id
|
||||
);
|
||||
const isTelurQty =
|
||||
so.marketing_type?.value?.toLowerCase() === 'telur' &&
|
||||
so.convertion_unit?.value?.toLowerCase() === 'qty';
|
||||
const salesOrderUnitPrice =
|
||||
isTelurQty && Number(so.total_price || 0) > 0 && Number(so.qty || 0) > 0
|
||||
? Number(so.total_price) / Number(so.qty)
|
||||
: so.unit_price;
|
||||
const salesOrderPricePerQty =
|
||||
isTelurQty &&
|
||||
Number(so.total_price || 0) > 0 &&
|
||||
Number(so.total_weight || 0) > 0
|
||||
? Number(so.total_price) / Number(so.total_weight)
|
||||
: so.price_per_qty;
|
||||
|
||||
return {
|
||||
...so, // nilai dasar dari sales order
|
||||
@@ -201,30 +227,30 @@ export const mergeSOwithDO = (
|
||||
delivery_date: delivery?.delivery_date || undefined,
|
||||
do_number: delivery?.do_number || undefined,
|
||||
vehicle_number: delivery?.vehicle_number || so.vehicle_number,
|
||||
unit_price: autofill ? so.unit_price : delivery?.unit_price,
|
||||
total_weight: autofill ? so.total_weight : delivery?.total_weight,
|
||||
qty: autofill ? so.qty : delivery?.qty,
|
||||
avg_weight: autofill ? so.avg_weight : delivery?.avg_weight,
|
||||
total_price: autofill ? so.total_price : delivery?.total_price,
|
||||
unit_price: autofill ? delivery?.unit_price : salesOrderUnitPrice,
|
||||
total_weight: autofill ? delivery?.total_weight : so.total_weight,
|
||||
qty: autofill ? delivery?.qty : so.qty,
|
||||
avg_weight: autofill ? delivery?.avg_weight : so.avg_weight,
|
||||
total_price: autofill ? delivery?.total_price : so.total_price,
|
||||
marketing_product: so, // jika ada, override
|
||||
uom: autofill ? so.uom : delivery?.uom,
|
||||
uom: autofill ? delivery?.uom : so.uom,
|
||||
weight_per_convertion: autofill
|
||||
? so.weight_per_convertion
|
||||
: delivery?.weight_per_convertion,
|
||||
? delivery?.weight_per_convertion
|
||||
: so.weight_per_convertion,
|
||||
price_per_convertion: autofill
|
||||
? so.price_per_convertion
|
||||
: delivery?.price_per_convertion,
|
||||
? delivery?.price_per_convertion
|
||||
: so.price_per_convertion,
|
||||
convertion_unit: autofill
|
||||
? so.convertion_unit
|
||||
: delivery?.convertion_unit,
|
||||
marketing_type: autofill ? so.marketing_type : delivery?.marketing_type,
|
||||
total_peti: autofill ? so.total_peti : delivery?.total_peti,
|
||||
price_per_qty: autofill ? so.price_per_qty : delivery?.price_per_qty,
|
||||
sisa_berat: autofill ? so.sisa_berat : delivery?.sisa_berat,
|
||||
? delivery?.convertion_unit
|
||||
: so.convertion_unit,
|
||||
marketing_type: autofill ? delivery?.marketing_type : so.marketing_type,
|
||||
total_peti: autofill ? delivery?.total_peti : so.total_peti,
|
||||
price_per_qty: autofill ? delivery?.price_per_qty : salesOrderPricePerQty,
|
||||
sisa_berat: autofill ? delivery?.sisa_berat : so.sisa_berat,
|
||||
price_sisa_berat: autofill
|
||||
? so.price_sisa_berat
|
||||
: delivery?.price_sisa_berat,
|
||||
week: autofill ? so.week : delivery?.week,
|
||||
? delivery?.price_sisa_berat
|
||||
: so.price_sisa_berat,
|
||||
week: autofill ? delivery?.week : so.week,
|
||||
} as DeliveryOrderProductFormValues;
|
||||
});
|
||||
};
|
||||
|
||||
+122
-36
@@ -32,6 +32,63 @@ import Dropdown from '@/components/Dropdown';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { handleMarketingCalculation } from '@/lib/marketing-calculation';
|
||||
|
||||
type PricingOption =
|
||||
| string
|
||||
| {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
| null
|
||||
| undefined;
|
||||
|
||||
type PricingSource =
|
||||
| {
|
||||
marketing_type?: PricingOption;
|
||||
convertion_unit?: PricingOption;
|
||||
total_price?: string | number | null;
|
||||
qty?: string | number | null;
|
||||
total_weight?: string | number | null;
|
||||
unit_price?: string | number | null;
|
||||
price_per_qty?: number | null;
|
||||
}
|
||||
| null
|
||||
| undefined;
|
||||
|
||||
const getOptionValue = (value?: PricingOption) => {
|
||||
if (!value) return undefined;
|
||||
if (typeof value === 'string') return value.toLowerCase();
|
||||
|
||||
return value.value?.toLowerCase();
|
||||
};
|
||||
|
||||
const isTelurQtyProduct = (value?: PricingSource) =>
|
||||
getOptionValue(value?.marketing_type) === 'telur' &&
|
||||
getOptionValue(value?.convertion_unit) === 'qty';
|
||||
|
||||
const getDisplayedUnitPrice = (value?: PricingSource) => {
|
||||
if (
|
||||
isTelurQtyProduct(value) &&
|
||||
Number(value?.total_price || 0) > 0 &&
|
||||
Number(value?.qty || 0) > 0
|
||||
) {
|
||||
return Number(value?.total_price) / Number(value?.qty);
|
||||
}
|
||||
|
||||
return value?.unit_price ?? undefined;
|
||||
};
|
||||
|
||||
const getDisplayedPricePerQty = (value?: PricingSource) => {
|
||||
if (
|
||||
isTelurQtyProduct(value) &&
|
||||
Number(value?.total_price || 0) > 0 &&
|
||||
Number(value?.total_weight || 0) > 0
|
||||
) {
|
||||
return Number(value?.total_price) / Number(value?.total_weight);
|
||||
}
|
||||
|
||||
return value?.price_per_qty ?? null;
|
||||
};
|
||||
|
||||
const DeliveryOrderProductForm = ({
|
||||
formState,
|
||||
salesOrders,
|
||||
@@ -69,14 +126,18 @@ const DeliveryOrderProductForm = ({
|
||||
Number(initialValues.total_peti)
|
||||
: 0;
|
||||
|
||||
const initialPricePerConvertion =
|
||||
initialValues?.total_price &&
|
||||
initialValues?.total_peti &&
|
||||
Number(initialValues.total_peti) !== 0
|
||||
? (Number(initialValues.total_price) -
|
||||
initialSisaBerat * Number(initialValues.unit_price || 0)) /
|
||||
Number(initialValues.total_peti)
|
||||
: 0;
|
||||
// const initialPricePerConvertion =
|
||||
// initialValues?.total_price &&
|
||||
// initialValues?.total_peti &&
|
||||
// Number(initialValues.total_peti) !== 0
|
||||
// ? (Number(initialValues.total_price) -
|
||||
// initialSisaBerat * Number(initialValues.unit_price || 0)) /
|
||||
// Number(initialValues.total_peti)
|
||||
// : 0;
|
||||
|
||||
const initialPricePerConvertion = initialValues?.unit_price
|
||||
? Number(initialValues?.unit_price)
|
||||
: 0;
|
||||
|
||||
const initialPriceSisaBerat =
|
||||
initialValues?.total_price && initialValues?.total_peti
|
||||
@@ -154,6 +215,27 @@ const DeliveryOrderProductForm = ({
|
||||
(item) => item.id === initialValues?.marketing_product_id
|
||||
);
|
||||
|
||||
const defaultPricingSource: PricingSource = {
|
||||
marketing_type:
|
||||
initialValues?.marketing_type ?? salesOrder?.marketing_type ?? null,
|
||||
convertion_unit:
|
||||
initialValues?.convertion_unit ?? salesOrder?.convertion_unit ?? null,
|
||||
total_price:
|
||||
deliveryOrder?.total_price ??
|
||||
initialValues?.total_price ??
|
||||
salesOrder?.total_price,
|
||||
qty: deliveryOrder?.qty ?? initialValues?.qty ?? salesOrder?.qty,
|
||||
total_weight:
|
||||
deliveryOrder?.total_weight ??
|
||||
initialValues?.total_weight ??
|
||||
salesOrder?.total_weight,
|
||||
unit_price:
|
||||
deliveryOrder?.unit_price ??
|
||||
initialValues?.unit_price ??
|
||||
salesOrder?.unit_price,
|
||||
price_per_qty: initialValues?.price_per_qty ?? null,
|
||||
};
|
||||
|
||||
const formik = useFormik<DeliveryOrderProductFormValues>({
|
||||
enableReinitialize: true,
|
||||
initialValues: {
|
||||
@@ -167,8 +249,7 @@ const DeliveryOrderProductForm = ({
|
||||
undefined,
|
||||
marketing_product_id:
|
||||
salesOrder?.id || initialValues?.marketing_product_id || undefined,
|
||||
unit_price:
|
||||
deliveryOrder?.unit_price ?? initialValues?.unit_price ?? undefined,
|
||||
unit_price: getDisplayedUnitPrice(defaultPricingSource),
|
||||
total_weight:
|
||||
deliveryOrder?.total_weight ?? initialValues?.total_weight ?? undefined,
|
||||
qty: deliveryOrder?.qty ?? initialValues?.qty ?? undefined,
|
||||
@@ -186,7 +267,7 @@ const DeliveryOrderProductForm = ({
|
||||
convertion_unit: initialValues?.convertion_unit || null,
|
||||
marketing_type: initialValues?.marketing_type || null,
|
||||
total_peti: initialValues?.total_peti ?? null,
|
||||
price_per_qty: initialValues?.price_per_qty ?? null,
|
||||
price_per_qty: getDisplayedPricePerQty(defaultPricingSource),
|
||||
sisa_berat: initialSisaBerat,
|
||||
price_sisa_berat: initialPriceSisaBerat,
|
||||
week: initialValues?.week ?? null,
|
||||
@@ -329,7 +410,11 @@ const DeliveryOrderProductForm = ({
|
||||
if (!Boolean(initialValues.qty)) {
|
||||
handleResetForm();
|
||||
} else {
|
||||
setFormikValues(initialValues);
|
||||
setFormikValues({
|
||||
...initialValues,
|
||||
unit_price: getDisplayedUnitPrice(initialValues),
|
||||
price_per_qty: getDisplayedPricePerQty(initialValues),
|
||||
});
|
||||
if (initialValues?.marketing_product_id) {
|
||||
setSelectedProduct({
|
||||
value: initialValues?.id,
|
||||
@@ -458,10 +543,11 @@ const DeliveryOrderProductForm = ({
|
||||
marketing_product_id: selected.value as number,
|
||||
marketing_product: soFieldValues,
|
||||
qty: so.qty,
|
||||
unit_price: so.unit_price,
|
||||
unit_price: getDisplayedUnitPrice(so),
|
||||
total_price: so.total_price,
|
||||
avg_weight: so.avg_weight,
|
||||
total_weight: so.total_weight,
|
||||
price_per_qty: getDisplayedPricePerQty(so),
|
||||
vehicle_number: so.vehicle_number,
|
||||
week: soFieldValues.week ?? null,
|
||||
});
|
||||
@@ -761,12 +847,32 @@ const DeliveryOrderProductForm = ({
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Harga per butir untuk TELUR + QTY */}
|
||||
{/* Harga Satuan */}
|
||||
{formik.values.convertion_unit?.value.toLowerCase() !== 'peti' &&
|
||||
formik.values.convertion_unit?.value.toLowerCase() !== 'kg' && (
|
||||
<NumberInput
|
||||
required
|
||||
label={`Harga / ${formik.values.convertion_unit?.label.toLowerCase() !== 'qty' ? 'Kg' : 'Butir'} (Rp)`}
|
||||
name='unit_price'
|
||||
value={formik.values.unit_price}
|
||||
onChange={(e) => {
|
||||
const value = Number(e.target.value);
|
||||
handleFieldChange('unit_price', value, () =>
|
||||
setCurrentInput(e.target.name)
|
||||
);
|
||||
}}
|
||||
isError={Boolean(formik.errors.unit_price)}
|
||||
errorMessage={formik.errors.unit_price}
|
||||
placeholder='Masukan Harga Satuan'
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Harga per kg untuk TELUR + QTY */}
|
||||
{formik.values.marketing_type?.value.toLowerCase() === 'telur' &&
|
||||
formik.values.convertion_unit?.value.toLowerCase() === 'qty' && (
|
||||
<NumberInput
|
||||
required
|
||||
label='Harga / Butir (Rp)'
|
||||
label='Harga / Kg (Rp)'
|
||||
name='price_per_qty'
|
||||
value={formik.values.price_per_qty ?? undefined}
|
||||
onChange={(e) => {
|
||||
@@ -780,27 +886,7 @@ const DeliveryOrderProductForm = ({
|
||||
Boolean(formik.errors.price_per_qty)
|
||||
}
|
||||
errorMessage={formik.errors.price_per_qty}
|
||||
placeholder='Masukan Harga per Butir'
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Harga Satuan */}
|
||||
{formik.values.convertion_unit?.value.toLowerCase() !== 'peti' &&
|
||||
formik.values.convertion_unit?.value.toLowerCase() !== 'kg' && (
|
||||
<NumberInput
|
||||
required
|
||||
label={`Harga / ${isResponseSuccess(productData) ? productData?.data?.uom?.name : 'Produk'} (Rp)`}
|
||||
name='unit_price'
|
||||
value={formik.values.unit_price}
|
||||
onChange={(e) => {
|
||||
const value = Number(e.target.value);
|
||||
handleFieldChange('unit_price', value, () =>
|
||||
setCurrentInput(e.target.name)
|
||||
);
|
||||
}}
|
||||
isError={Boolean(formik.errors.unit_price)}
|
||||
errorMessage={formik.errors.unit_price}
|
||||
placeholder='Masukan Harga Satuan'
|
||||
placeholder='Masukan Harga per Kg'
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ import { Icon } from '@iconify/react';
|
||||
import { useRef, useMemo } from 'react';
|
||||
import { formatCurrency, formatDate, formatNumber } from '@/lib/helper';
|
||||
import DeliveryOrderExport from '@/components/pages/marketing/pdf/DeliveryOrderExport';
|
||||
import { Marketing, BaseDelivery } from '@/types/api/marketing/marketing';
|
||||
import { Marketing } from '@/types/api/marketing/marketing';
|
||||
import { Warehouse } from '@/types/api/master-data/warehouse';
|
||||
import { DeliveryProductToFieldValues } from '@/components/pages/marketing/form/MarketingForm.schema';
|
||||
|
||||
type DeliveryOrderProductTableProps = {
|
||||
data: DeliveryOrderProductFormValues[];
|
||||
@@ -55,14 +56,17 @@ const DeliveryOrderProductTable = ({
|
||||
|
||||
const deliveryItems = useMemo(() => {
|
||||
if (!hasDeliveryOrder) return [];
|
||||
|
||||
return (
|
||||
marketing?.delivery_order?.flatMap((doItem) =>
|
||||
doItem.deliveries.map((delivery) => ({
|
||||
...delivery,
|
||||
do_number: doItem.do_number,
|
||||
delivery_date: doItem.delivery_date,
|
||||
warehouse: doItem.warehouse,
|
||||
}))
|
||||
DeliveryProductToFieldValues(marketing?.sales_order, doItem).map(
|
||||
(delivery) => ({
|
||||
...delivery,
|
||||
do_number: doItem.do_number,
|
||||
delivery_date: doItem.delivery_date,
|
||||
warehouse: doItem.warehouse,
|
||||
})
|
||||
)
|
||||
) ?? []
|
||||
);
|
||||
}, [marketing?.delivery_order, hasDeliveryOrder]);
|
||||
@@ -212,7 +216,7 @@ const DeliveryOrderProductTable = ({
|
||||
};
|
||||
|
||||
const renderDeliveryOrderContent = (
|
||||
item: BaseDelivery & {
|
||||
item: DeliveryOrderProductFormValues & {
|
||||
do_number: string;
|
||||
delivery_date: string;
|
||||
warehouse: Warehouse;
|
||||
@@ -231,6 +235,24 @@ const DeliveryOrderProductTable = ({
|
||||
<th className='text-start font-medium text-base-content/50 text-sm px-4 py-3'>
|
||||
<div className='flex w-full flex-row gap-1 items-center justify-between h-full'>
|
||||
<div>Value</div>
|
||||
{formType !== 'success' &&
|
||||
(formType === 'add_delivery' ||
|
||||
formType === 'edit_delivery' ||
|
||||
formType === 'detail') && (
|
||||
<div className='flex flex-row gap-1.5 items-center'>
|
||||
<Button
|
||||
type='button'
|
||||
variant='ghost'
|
||||
color='none'
|
||||
onClick={() => {
|
||||
onEditRef.current(item.id as number, item);
|
||||
}}
|
||||
className='p-0 hover:text-base-content'
|
||||
>
|
||||
<Icon icon='heroicons:pencil' width={20} height={20} />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
@@ -242,14 +264,14 @@ const DeliveryOrderProductTable = ({
|
||||
<tr>
|
||||
<td className='text-sm px-4 py-3'>Produk</td>
|
||||
<td className='text-sm px-4 py-3'>
|
||||
{item.product_warehouse?.product?.name}
|
||||
{item.marketing_product?.product_warehouse_data?.product.name}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className='text-sm px-4 py-3'>Qty</td>
|
||||
<td className='text-sm px-4 py-3'>
|
||||
{item.qty
|
||||
? `${formatNumber(item.qty)} ${item.product_warehouse?.product?.uom?.name ?? ''}`
|
||||
? `${formatNumber(Number(item.qty))} ${item.marketing_product?.product_warehouse_data?.product.uom.name ?? ''}`
|
||||
: '-'}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -272,13 +294,13 @@ const DeliveryOrderProductTable = ({
|
||||
<tr>
|
||||
<td className='text-sm px-4 py-3'>Total Harga Satuan</td>
|
||||
<td className='text-sm px-4 py-3'>
|
||||
{formatCurrency(item.unit_price)}
|
||||
{formatCurrency(Number(item.unit_price))}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className='text-sm px-4 py-3'>Total Penjualan</td>
|
||||
<td className='text-sm px-4 py-3'>
|
||||
{formatCurrency(item.total_price)}
|
||||
{formatCurrency(Number(item.total_price))}
|
||||
</td>
|
||||
</tr>
|
||||
</>
|
||||
@@ -334,7 +356,9 @@ const DeliveryOrderProductTable = ({
|
||||
<div className='size-full flex flex-col relative overflow-x-hidden gap-3'>
|
||||
{hasDeliveryOrder
|
||||
? deliveryItems.map((item, index) => (
|
||||
<div key={`do-table-${item.product_warehouse?.id}-${index}`}>
|
||||
<div
|
||||
key={`do-table-${item.marketing_product?.product_warehouse?.value}-${index}`}
|
||||
>
|
||||
{formType === 'success' ? (
|
||||
<div className='rounded-lg border border-tools-table-outline border-base-content/5'>
|
||||
<table
|
||||
@@ -350,8 +374,11 @@ const DeliveryOrderProductTable = ({
|
||||
</div>
|
||||
) : (
|
||||
<Card
|
||||
key={`do-table-${item.product_warehouse?.id}-${index}`}
|
||||
title={item.product_warehouse?.product?.name || 'Produk'}
|
||||
key={`do-table-${item.marketing_product?.product_warehouse?.value}-${index}`}
|
||||
title={
|
||||
item.marketing_product?.product_warehouse_data?.product
|
||||
.name || 'Produk'
|
||||
}
|
||||
collapsible={true}
|
||||
defaultCollapsed={false}
|
||||
variant='bordered'
|
||||
|
||||
Reference in New Issue
Block a user