fix(medical-store): fix item rate picking and batch pricing when loading Mobile Draft bills into POS cart
This commit is contained in:
parent
e4e89fb34a
commit
bc90020c69
|
|
@ -5974,7 +5974,8 @@ class MedicalStoreApi extends BaseController
|
|||
foreach ($items as $it) {
|
||||
$qty = (float)($it['qty'] ?? 1);
|
||||
$rate = (float)($it['effective_rate'] ?? ($it['unit_price'] ?? ($it['mrp'] ?? 0)));
|
||||
$estAmount += ($qty * $rate);
|
||||
$lineGross = (float)($it['line_gross'] ?? ($qty * $rate));
|
||||
$estAmount += $lineGross;
|
||||
}
|
||||
|
||||
$this->db->table('mst_draft_bills')->insert([
|
||||
|
|
@ -6021,8 +6022,82 @@ class MedicalStoreApi extends BaseController
|
|||
->getResultArray();
|
||||
|
||||
foreach ($drafts as &$d) {
|
||||
$d['items'] = json_decode($d['items_json'], true) ?: [];
|
||||
$items = json_decode($d['items_json'], true) ?: [];
|
||||
|
||||
// Gather missing info from batches and items for draft lines
|
||||
$batchIds = array_filter(array_column($items, 'batch_id'));
|
||||
$itemIds = array_filter(array_column($items, 'item_id'));
|
||||
|
||||
$batchMap = [];
|
||||
if (!empty($batchIds)) {
|
||||
$bRows = $this->db->table('mst_batches')
|
||||
->select('batch_id, item_id, batch_no, expiry_date, mrp, ptr, gst_rate')
|
||||
->whereIn('batch_id', $batchIds)
|
||||
->get()->getResultArray();
|
||||
foreach ($bRows as $br) {
|
||||
$batchMap[$br['batch_id']] = $br;
|
||||
}
|
||||
}
|
||||
|
||||
$itemMap = [];
|
||||
if (!empty($itemIds)) {
|
||||
$iRows = $this->db->table('mst_items')
|
||||
->select('item_id, item_name, generic_name, unit_pack, units_per_pack, drug_schedule, hsn_code, gst_rate')
|
||||
->whereIn('item_id', $itemIds)
|
||||
->get()->getResultArray();
|
||||
foreach ($iRows as $ir) {
|
||||
$itemMap[$ir['item_id']] = $ir;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($items as &$it) {
|
||||
$b = $batchMap[$it['batch_id'] ?? 0] ?? null;
|
||||
$m = $itemMap[$it['item_id'] ?? 0] ?? null;
|
||||
|
||||
$upp = (int)($it['units_per_pack'] ?? ($m['units_per_pack'] ?? 1));
|
||||
if ($upp < 1) $upp = 1;
|
||||
$it['units_per_pack'] = $upp;
|
||||
|
||||
$stripMrp = (float)($it['unit_mrp'] ?? ($b['mrp'] ?? ($it['mrp'] ?? 0)));
|
||||
if ($stripMrp <= 0 && isset($it['effective_rate']) && (float)$it['effective_rate'] > 0) {
|
||||
$stripMrp = ($it['sell_unit'] ?? '') === 'Tablet' ? round((float)$it['effective_rate'] * $upp, 2) : (float)$it['effective_rate'];
|
||||
}
|
||||
if ($stripMrp <= 0 && isset($it['line_gross']) && (float)$it['line_gross'] > 0) {
|
||||
$stripMrp = (float)$it['line_gross'];
|
||||
}
|
||||
|
||||
$it['unit_mrp'] = $stripMrp;
|
||||
$it['mrp'] = $stripMrp;
|
||||
|
||||
$sellUnit = $it['sell_unit'] ?? ($upp > 1 ? 'Tablet' : 'Unit');
|
||||
$it['sell_unit'] = $sellUnit;
|
||||
$q = max(1, (float)($it['qty'] ?? 1));
|
||||
$it['qty'] = $q;
|
||||
$it['strip_qty'] = $sellUnit === 'Strip' ? $q : (float)($it['strip_qty'] ?? 0);
|
||||
$it['loose_qty'] = ($sellUnit === 'Tablet' || $sellUnit === 'Unit') ? $q : (float)($it['loose_qty'] ?? 0);
|
||||
|
||||
if (!isset($it['gst_rate']) || $it['gst_rate'] === null) {
|
||||
$it['gst_rate'] = (float)($b['gst_rate'] ?? ($m['gst_rate'] ?? 12.0));
|
||||
}
|
||||
if (empty($it['hsn_code'])) {
|
||||
$it['hsn_code'] = $m['hsn_code'] ?? '3004';
|
||||
}
|
||||
if (empty($it['unit_pack'])) {
|
||||
$it['unit_pack'] = $m['unit_pack'] ?? ($upp > 1 ? "Pack: {$upp} Tabs" : 'Unit');
|
||||
}
|
||||
if (empty($it['drug_schedule'])) {
|
||||
$it['drug_schedule'] = $m['drug_schedule'] ?? '';
|
||||
}
|
||||
if (empty($it['expiry_display']) && !empty($it['expiry_date'])) {
|
||||
$it['expiry_display'] = date('m/Y', strtotime($it['expiry_date']));
|
||||
}
|
||||
}
|
||||
unset($it);
|
||||
|
||||
$d['items'] = $items;
|
||||
$d['items_json'] = json_encode($items);
|
||||
}
|
||||
unset($d);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 1,
|
||||
|
|
|
|||
|
|
@ -1543,18 +1543,56 @@ function PosCounter({ store, notify, initialEditInvoice, onClearEditInvoice, act
|
|||
|
||||
const handleLoadDraftBillIntoCart = (draft) => {
|
||||
try {
|
||||
const items = typeof draft.items_json === 'string' ? JSON.parse(draft.items_json) : draft.items_json;
|
||||
if (!Array.isArray(items) || items.length === 0) {
|
||||
const rawItems = typeof draft.items_json === 'string' ? JSON.parse(draft.items_json) : (draft.items || draft.items_json);
|
||||
if (!Array.isArray(rawItems) || rawItems.length === 0) {
|
||||
notify('Draft contains no items.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const formattedCart = items.map((it, idx) => ({
|
||||
...it,
|
||||
cart_item_id: Date.now() + '_' + idx,
|
||||
discount_type: it.discount_type || 'NONE',
|
||||
discount_val: Number(it.discount_val) || 0
|
||||
}));
|
||||
const formattedCart = rawItems.map((it, idx) => {
|
||||
const upp = Number(it.units_per_pack) > 0 ? Number(it.units_per_pack) : 1;
|
||||
const sellUnit = it.sell_unit || (upp > 1 ? 'Tablet' : 'Unit');
|
||||
const q = Math.max(1, Number(it.qty) || 1);
|
||||
|
||||
// Resiliently resolve strip MRP (unit_mrp)
|
||||
let unitMrp = Number(it.unit_mrp ?? it.mrp ?? 0);
|
||||
if (unitMrp <= 0) {
|
||||
if (Number(it.effective_rate) > 0) {
|
||||
unitMrp = sellUnit === 'Tablet' ? Number((Number(it.effective_rate) * upp).toFixed(2)) : Number(it.effective_rate);
|
||||
} else if (Number(it.line_gross) > 0) {
|
||||
unitMrp = sellUnit === 'Tablet' ? Number(it.line_gross) : Number((Number(it.line_gross) / q).toFixed(2));
|
||||
}
|
||||
}
|
||||
|
||||
const stripQty = sellUnit === 'Strip' ? q : (Number(it.strip_qty) || 0);
|
||||
const looseQty = (sellUnit === 'Tablet' || sellUnit === 'Unit') ? q : (Number(it.loose_qty) || 0);
|
||||
|
||||
return {
|
||||
...it,
|
||||
cart_item_id: Date.now() + '_' + idx + '_' + Math.random().toString(36).substr(2, 4),
|
||||
item_id: it.item_id,
|
||||
item_name: it.item_name,
|
||||
generic_name: it.generic_name || '',
|
||||
unit_pack: it.unit_pack || (upp > 1 ? `Pack: ${upp} Tabs` : 'Unit'),
|
||||
units_per_pack: upp,
|
||||
drug_schedule: it.drug_schedule || '',
|
||||
hsn_code: it.hsn_code || '3004',
|
||||
gst_rate: it.gst_rate !== undefined && it.gst_rate !== null ? Number(it.gst_rate) : 12.0,
|
||||
batch_id: it.batch_id,
|
||||
batch_no: it.batch_no,
|
||||
expiry_display: it.expiry_display || (it.expiry_date ? it.expiry_date.substring(0, 7) : ''),
|
||||
expiry_date: it.expiry_date || '',
|
||||
current_qty: Number(it.current_qty) || 9999,
|
||||
unit_mrp: unitMrp,
|
||||
mrp: unitMrp,
|
||||
sell_unit: sellUnit,
|
||||
strip_qty: stripQty,
|
||||
loose_qty: looseQty,
|
||||
qty: q,
|
||||
discount_type: it.discount_type || 'pct',
|
||||
discount_val: Number(it.discount_val) || 0
|
||||
};
|
||||
});
|
||||
|
||||
setCart(formattedCart);
|
||||
if (draft.patient_name) setPatientQuery(draft.patient_name);
|
||||
|
|
@ -1563,7 +1601,7 @@ function PosCounter({ store, notify, initialEditInvoice, onClearEditInvoice, act
|
|||
if (draft.doctor_name) setDoctorName(draft.doctor_name);
|
||||
|
||||
setShowDraftModal(false);
|
||||
notify(`Draft [${draft.draft_code}] with ${items.length} items loaded into billing cart!`, 'success');
|
||||
notify(`Draft [${draft.draft_code}] with ${rawItems.length} items loaded into billing cart!`, 'success');
|
||||
} catch (err) {
|
||||
notify('Failed to load draft items: ' + err.message, 'error');
|
||||
}
|
||||
|
|
@ -14804,22 +14842,35 @@ function MobileAppView({ store, stores, notify, activeOperator, onSwitchOperator
|
|||
}
|
||||
|
||||
const upp = Number(selectedItem.units_per_pack || selectedBatch.units_per_pack || 1);
|
||||
const stripMrp = Number(selectedBatch.mrp || 0);
|
||||
const perUnitMrp = upp > 0 ? (stripMrp / upp) : stripMrp;
|
||||
const totalUnits = collectUnit === 'Strip' ? (q * upp) : q;
|
||||
const rate = Number(selectedBatch.mrp || 0) / (collectUnit === 'Strip' ? 1 : upp);
|
||||
const rate = collectUnit === 'Strip' ? stripMrp : perUnitMrp;
|
||||
const lineGross = collectUnit === 'Strip' ? (q * stripMrp) : (q * perUnitMrp);
|
||||
|
||||
const newItem = {
|
||||
item_id: selectedItem.item_id,
|
||||
item_name: selectedItem.item_name,
|
||||
generic_name: selectedItem.generic_name || '',
|
||||
unit_pack: selectedItem.unit_pack || (upp > 1 ? `Pack: ${upp} Tabs` : 'Unit'),
|
||||
units_per_pack: upp,
|
||||
drug_schedule: selectedItem.drug_schedule || '',
|
||||
hsn_code: selectedItem.hsn_code || '3004',
|
||||
gst_rate: Number(selectedBatch.gst_rate ?? selectedItem.gst_rate ?? 12.0),
|
||||
batch_id: selectedBatch.batch_id,
|
||||
batch_no: selectedBatch.batch_no,
|
||||
expiry_display: selectedBatch.expiry_display || (selectedBatch.expiry_date ? selectedBatch.expiry_date.substring(0, 7) : ''),
|
||||
expiry_date: selectedBatch.expiry_date,
|
||||
current_qty: selectedBatch.current_qty || 0,
|
||||
unit_mrp: stripMrp,
|
||||
mrp: stripMrp,
|
||||
qty: q,
|
||||
sell_unit: collectUnit,
|
||||
units_per_pack: upp,
|
||||
strip_qty: collectUnit === 'Strip' ? q : 0,
|
||||
loose_qty: (collectUnit === 'Tablet' || collectUnit === 'Unit') ? q : 0,
|
||||
total_units: totalUnits,
|
||||
effective_rate: rate,
|
||||
line_gross: q * Number(selectedBatch.mrp || 0)
|
||||
effective_rate: Number(rate.toFixed(2)),
|
||||
line_gross: Number(lineGross.toFixed(2))
|
||||
};
|
||||
|
||||
setCollectorItems(prev => [...prev, newItem]);
|
||||
|
|
@ -15330,7 +15381,7 @@ function MobileAppView({ store, stores, notify, activeOperator, onSwitchOperator
|
|||
<div>
|
||||
<div className="fw-bold text-white">{it.item_name}</div>
|
||||
<div className="text-slate-400" style={{ fontSize: '0.7rem' }}>
|
||||
Batch: {it.batch_no} • Qty: <strong className="text-cyan-300">{it.qty} {it.sell_unit}</strong> ({it.total_units} total units)
|
||||
Batch: {it.batch_no} • Qty: <strong className="text-cyan-300">{it.qty} {it.sell_unit}</strong> • Rate: <strong className="text-warning">₹{it.effective_rate}</strong> • Total: <strong className="text-success">₹{it.line_gross}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user