Fix pharmacy stock sync for invoice, purchase edit, challan and return flows

This commit is contained in:
DevSoftTech Server 2026-06-20 11:25:40 +05:30
parent fe2fabc5b8
commit 8fc60e893e

View File

@ -1722,6 +1722,8 @@ class Medical extends BaseController
$this->db->table('inv_med_item')->insert($insert);
$this->syncPurchaseItemSaleUnits((int) ($stock->stock_id ?? 0));
$this->recalculateInvoiceTotals($invoiceId);
return redirect()->to(base_url('Medical/invoice_edit/' . $invoiceId . '?msg=' . urlencode('Item added')));
@ -1763,6 +1765,10 @@ class Medical extends BaseController
->where('inv_med_id', $invoiceId)
->delete();
if ($itemRow) {
$this->syncPurchaseItemSaleUnits((int) ($itemRow['store_stock_id'] ?? 0));
}
if ($itemRow) {
$this->archiveDeletedInvoiceItem($itemRow);
@ -1882,6 +1888,8 @@ class Medical extends BaseController
$this->db->table('inv_med_item')->where('id', $itemId)->update($update);
$this->syncPurchaseItemSaleUnits((int) ($item->store_stock_id ?? 0));
$this->recalculateInvoiceTotals($invoiceId);
$itemName = (string) ($item->item_Name ?? 'Item');
@ -2038,11 +2046,69 @@ class Medical extends BaseController
return $respond(0, 'Not Done');
}
$this->syncPurchaseItemSaleUnits((int) ($source['store_stock_id'] ?? 0));
$this->recalculateInvoiceTotals($invoiceId);
return $respond($updatedId, $msgText);
}
private function syncPurchaseItemSaleUnits(int $purchaseItemId): void
{
if ($purchaseItemId <= 0 || ! $this->db->tableExists('purchase_invoice_item')) {
return;
}
// Try legacy procedure first; then verify and enforce if mismatch remains.
try {
$medicalModel = new MedicalModel();
$medicalModel->updatePurchaseStockById($purchaseItemId);
} catch (\Throwable $e) {
log_message('error', 'Stock sync via procedure failed: ' . $e->getMessage());
}
if (! $this->db->tableExists('inv_med_item')) {
return;
}
$purchaseFields = $this->db->getFieldNames('purchase_invoice_item') ?? [];
if (! in_array('total_sale_unit', $purchaseFields, true)) {
return;
}
$itemFields = $this->db->getFieldNames('inv_med_item') ?? [];
$sumSql = 'SUM(CASE WHEN IFNULL(sale_return,0)=1 OR IFNULL(amount,0)<0 THEN IFNULL(qty,0)*-1 ELSE IFNULL(qty,0) END) AS sold_qty';
if (! in_array('sale_return', $itemFields, true)) {
$sumSql = 'SUM(CASE WHEN IFNULL(amount,0)<0 THEN IFNULL(qty,0)*-1 ELSE IFNULL(qty,0) END) AS sold_qty';
}
$soldRow = $this->db->table('inv_med_item')
->select($sumSql, false)
->where('store_stock_id', $purchaseItemId)
->get()
->getRow();
$soldQty = max(0.0, (float) ($soldRow->sold_qty ?? 0));
$stockRow = $this->db->table('purchase_invoice_item')
->select('id,total_sale_unit')
->where('id', $purchaseItemId)
->get()
->getRow();
if (! $stockRow) {
return;
}
$currentSaleQty = (float) ($stockRow->total_sale_unit ?? 0);
if (abs($currentSaleQty - $soldQty) < 0.00001) {
return;
}
$this->db->table('purchase_invoice_item')
->where('id', $purchaseItemId)
->update(['total_sale_unit' => $soldQty]);
}
public function go_final()
{
if ($deny = $this->ensurePharmacyAccess()) {
@ -5386,10 +5452,11 @@ class Medical extends BaseController
// ── 1. Resolve gateway credentials ──────────────────────────────────
$gwUrl = '';
$gwToken = '';
$gwHfrId = '';
if ($this->db->tableExists('hospital_setting')) {
$hsRows = $this->db->table('hospital_setting')
->select('s_name, s_value')
->whereIn('s_name', ['EATRIA_BRIDGE_URL', 'EATRIA_BRIDGE_TOKEN'])
->whereIn('s_name', ['EATRIA_BRIDGE_URL', 'EATRIA_BRIDGE_TOKEN', 'ABDM_HFR_ID', 'H_HFR_ID'])
->get()
->getResultArray();
foreach ($hsRows as $hsRow) {
@ -5399,6 +5466,12 @@ class Medical extends BaseController
if ((string) ($hsRow['s_name'] ?? '') === 'EATRIA_BRIDGE_TOKEN') {
$gwToken = trim((string) ($hsRow['s_value'] ?? ''));
}
if ((string) ($hsRow['s_name'] ?? '') === 'ABDM_HFR_ID') {
$gwHfrId = trim((string) ($hsRow['s_value'] ?? ''));
}
if ((string) ($hsRow['s_name'] ?? '') === 'H_HFR_ID' && $gwHfrId === '') {
$gwHfrId = trim((string) ($hsRow['s_value'] ?? ''));
}
}
}
if ($gwUrl === '' || $gwToken === '') {
@ -5420,9 +5493,9 @@ class Medical extends BaseController
}
// ── 2. Fetch master lists from gateway (all pages) ───────────────────
$gatewayCompanyItems = $this->fetchAllGatewayDrugMasters($gwUrl, $gwToken, 'company');
$gatewayFormulationItems = $this->fetchAllGatewayDrugMasters($gwUrl, $gwToken, 'formulation');
$gatewayShortFormItems = $this->fetchAllGatewayDrugMasters($gwUrl, $gwToken, 'short_formulation');
$gatewayCompanyItems = $this->fetchAllGatewayDrugMasters($gwUrl, $gwToken, $gwHfrId, 'company');
$gatewayFormulationItems = $this->fetchAllGatewayDrugMasters($gwUrl, $gwToken, $gwHfrId, 'formulation');
$gatewayShortFormItems = $this->fetchAllGatewayDrugMasters($gwUrl, $gwToken, $gwHfrId, 'short_formulation');
if ($gatewayCompanyItems === null) {
return $this->response->setJSON([
@ -6527,15 +6600,18 @@ class Medical extends BaseController
*
* @return array<int,mixed>|null
*/
private function fetchAllGatewayDrugMasters(string $gwUrl, string $token, string $master): ?array
private function fetchAllGatewayDrugMasters(string $gwUrl, string $token, string $hfrId, string $master): ?array
{
$pageSize = 500;
$offset = 0;
$all = [];
do {
$url = rtrim($gwUrl, '/') . '/v3/drugs/masters?master=' . urlencode($master)
. '&limit=' . $pageSize . '&offset=' . $offset;
$url = rtrim($gwUrl, '/') . '/v3/drugs/masters?master=' . urlencode($master)
. '&limit=' . $pageSize . '&offset=' . $offset;
if ($hfrId !== '') {
$url .= '&hfr_id=' . urlencode($hfrId);
}
$ch = curl_init();
curl_setopt_array($ch, [
@ -6587,7 +6663,29 @@ class Medical extends BaseController
*/
private function callGatewayDrugMasters(string $gwUrl, string $token, string $master, int $limit): ?array
{
$hfrId = '';
if ($this->db->tableExists('hospital_setting')) {
$rows = $this->db->table('hospital_setting')
->select('s_name, s_value')
->whereIn('s_name', ['ABDM_HFR_ID', 'H_HFR_ID'])
->get()
->getResultArray();
foreach ($rows as $row) {
$sName = (string) ($row['s_name'] ?? '');
$sValue = trim((string) ($row['s_value'] ?? ''));
if ($sName === 'ABDM_HFR_ID') {
$hfrId = $sValue;
}
if ($sName === 'H_HFR_ID' && $hfrId === '') {
$hfrId = $sValue;
}
}
}
$url = rtrim($gwUrl, '/') . '/v3/drugs/masters?master=' . urlencode($master) . '&limit=' . (int) $limit;
if ($hfrId !== '') {
$url .= '&hfr_id=' . urlencode($hfrId);
}
$ch = curl_init();
curl_setopt_array($ch, [
@ -7818,6 +7916,8 @@ class Medical extends BaseController
'old_purchase_id' => $oldPurchaseId,
]);
$this->syncPurchaseItemSaleUnits($ssNo);
$this->recomputePurchaseInvoiceTotals($oldPurchaseId);
$this->recomputePurchaseInvoiceTotals($purchaseId);
@ -7851,6 +7951,8 @@ class Medical extends BaseController
'old_purchase_id' => 0,
]);
$this->syncPurchaseItemSaleUnits($ssNo);
$this->recomputePurchaseInvoiceTotals($currentPurchaseId);
$this->recomputePurchaseInvoiceTotals($oldPurchaseId);
@ -8020,6 +8122,7 @@ class Medical extends BaseController
}
if ($isUpdateStock > 0) {
$this->syncPurchaseItemSaleUnits((int) $isUpdateStock);
$this->recomputePurchaseInvoiceTotals($invId);
}
@ -8664,27 +8767,25 @@ class Medical extends BaseController
}
$fields = $this->db->getFieldNames('purchase_invoice_item') ?? [];
if (! in_array('total_return_unit', $fields, true)) {
return;
if (in_array('total_return_unit', $fields, true)) {
$row = $this->db->table('purchase_invoice_item')
->select('id,total_return_unit')
->where('id', $purchaseItemId)
->get()
->getRow();
if ($row) {
$nextQty = (float) ($row->total_return_unit ?? 0) + $qtyDelta;
if ($nextQty < 0) {
$nextQty = 0;
}
$this->db->table('purchase_invoice_item')
->where('id', $purchaseItemId)
->update(['total_return_unit' => $nextQty]);
}
}
$row = $this->db->table('purchase_invoice_item')
->select('id,total_return_unit')
->where('id', $purchaseItemId)
->get()
->getRow();
if (! $row) {
return;
}
$nextQty = (float) ($row->total_return_unit ?? 0) + $qtyDelta;
if ($nextQty < 0) {
$nextQty = 0;
}
$this->db->table('purchase_invoice_item')
->where('id', $purchaseItemId)
->update(['total_return_unit' => $nextQty]);
$this->syncPurchaseItemSaleUnits($purchaseItemId);
}
public function main_store_placeholder($slug = '')