feat(tax): standardize current GST slabs (0%, 5%, 18%, 40%, legacy 12%, 28%) across HMS and Medical Store
This commit is contained in:
parent
358416fc10
commit
5187fcf3ed
|
|
@ -531,20 +531,27 @@ class MedicalStoreApi extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
$gstRates = [0, 5, 12, 18, 28];
|
||||
// Current GST Slabs: 0% (Nil/Exempt), 5% (Common/Basic), 18% (Standard), 40% (Demerit/Sin), plus legacy 12% and 28%
|
||||
$gstRates = [0, 5, 18, 40, 12, 28];
|
||||
if ($this->db->tableExists('med_gst_per')) {
|
||||
$gRows = $this->db->table('med_gst_per')->select('gst_per')->orderBy('gst_per', 'ASC')->get()->getResultArray();
|
||||
if (!empty($gRows)) {
|
||||
$customRates = [];
|
||||
$mappedRates = [];
|
||||
foreach ($gRows as $gr) {
|
||||
$r = (float)$gr['gst_per'];
|
||||
if (!in_array($r, $customRates, true)) {
|
||||
$customRates[] = $r;
|
||||
$half = (float)$gr['gst_per'];
|
||||
$tot = round($half * 2, 2); // med_gst_per stores CGST half-rate
|
||||
if ($tot > 0 && !in_array($tot, $mappedRates)) {
|
||||
$mappedRates[] = $tot;
|
||||
}
|
||||
}
|
||||
if (!empty($customRates)) {
|
||||
$gstRates = $customRates;
|
||||
foreach ([0, 5, 18, 40, 12, 28] as $reqRate) {
|
||||
if (!in_array($reqRate, $mappedRates)) {
|
||||
$mappedRates[] = $reqRate;
|
||||
}
|
||||
}
|
||||
$mappedRates = array_values(array_unique($mappedRates));
|
||||
sort($mappedRates);
|
||||
$gstRates = $mappedRates;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11053,11 +11053,13 @@ class Medical extends BaseController
|
|||
$camt = (float) ($row['cgst_2_5'] ?? 0)
|
||||
+ (float) ($row['cgst_6'] ?? 0)
|
||||
+ (float) ($row['cgst_9'] ?? 0)
|
||||
+ (float) ($row['cgst_14'] ?? 0);
|
||||
+ (float) ($row['cgst_14'] ?? 0)
|
||||
+ (float) ($row['cgst_20'] ?? 0);
|
||||
$samt = (float) ($row['sgst_2_5'] ?? 0)
|
||||
+ (float) ($row['sgst_6'] ?? 0)
|
||||
+ (float) ($row['sgst_9'] ?? 0)
|
||||
+ (float) ($row['sgst_14'] ?? 0);
|
||||
+ (float) ($row['sgst_14'] ?? 0)
|
||||
+ (float) ($row['sgst_20'] ?? 0);
|
||||
|
||||
$hsnData[] = [
|
||||
'num' => $num++,
|
||||
|
|
@ -11240,6 +11242,9 @@ class Medical extends BaseController
|
|||
. 'ROUND(SUM(CASE WHEN ' . $cgstPerExpr . '=14 THEN ' . $taxableExpr . ' ELSE 0 END),0) AS sale_28_amount,'
|
||||
. 'SUM(CASE WHEN ' . $cgstPerExpr . '=14 THEN ' . $cgstExpr . ' ELSE 0 END) AS cgst_14,'
|
||||
. 'SUM(CASE WHEN ' . $cgstPerExpr . '=14 THEN ' . $sgstExpr . ' ELSE 0 END) AS sgst_14,'
|
||||
. 'ROUND(SUM(CASE WHEN ' . $cgstPerExpr . '=20 THEN ' . $taxableExpr . ' ELSE 0 END),0) AS sale_40_amount,'
|
||||
. 'SUM(CASE WHEN ' . $cgstPerExpr . '=20 THEN ' . $cgstExpr . ' ELSE 0 END) AS cgst_20,'
|
||||
. 'SUM(CASE WHEN ' . $cgstPerExpr . '=20 THEN ' . $sgstExpr . ' ELSE 0 END) AS sgst_20,'
|
||||
. 'ROUND(SUM(CASE WHEN ' . $cgstPerExpr . '=0 THEN ' . $taxableExpr . ' ELSE 0 END),0) AS sale_0_amount '
|
||||
. 'FROM invoice_med_master m '
|
||||
. 'JOIN inv_med_item i ON m.' . $mid . '=i.' . $invMedId . ' '
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class UpdateGstSlabsAcrossMasters extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// 1. Ensure med_gst_per exists and contains the current GST slabs (half-rates for CGST/SGST)
|
||||
// Slabs: 0% -> 0.00, 5% -> 2.50, 18% -> 9.00, 40% -> 20.00, 12% (legacy) -> 6.00, 28% (legacy) -> 14.00
|
||||
if ($this->db->tableExists('med_gst_per')) {
|
||||
$requiredRates = [
|
||||
0.00,
|
||||
2.50,
|
||||
6.00,
|
||||
9.00,
|
||||
14.00,
|
||||
20.00
|
||||
];
|
||||
|
||||
foreach ($requiredRates as $rate) {
|
||||
$row = $this->db->query("SELECT id FROM `med_gst_per` WHERE ROUND(`gst_per`, 2) = ROUND(?, 2) LIMIT 1", [$rate])->getRowArray();
|
||||
|
||||
if (!$row) {
|
||||
$this->db->table('med_gst_per')->insert([
|
||||
'gst_per' => $rate
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
// Keep rates for safety of historical data
|
||||
}
|
||||
}
|
||||
|
|
@ -121,33 +121,34 @@ $flag = static function ($v): string {
|
|||
<div class="col-md-1">
|
||||
<label class="form-label">CGST</label>
|
||||
<select class="form-select" name="input_CGST" id="input_CGST">
|
||||
<?php if (! empty($gstRates)): ?>
|
||||
<?php foreach ($gstRates as $rate): ?>
|
||||
<?php $gstValue = trim((string) ($rate->gst_per ?? '0')); ?>
|
||||
<?php if ($gstValue === '') { $gstValue = '0'; } ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === (float) $cgst) ? 'selected' : '' ?>><?= esc($gstValue) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<?php foreach (['0', '2.5', '5', '6', '9', '12'] as $gstValue): ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === (float) $cgst) ? 'selected' : '' ?>><?= esc($gstValue) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
$formatGstOptionLabel = static function($val) {
|
||||
$f = (float)$val;
|
||||
if ($f == 0.0) return '0% (Exempt)';
|
||||
if ($f == 2.5) return '2.5% (5% GST)';
|
||||
if ($f == 9.0) return '9.0% (18% GST)';
|
||||
if ($f == 20.0) return '20% (40% GST)';
|
||||
if ($f == 6.0) return '6.0% (12% Legacy)';
|
||||
if ($f == 14.0) return '14% (28% Legacy)';
|
||||
return $val . '%';
|
||||
};
|
||||
$standardGstValues = ['0', '2.5', '9', '20', '6', '14'];
|
||||
$rawRates = !empty($gstRates) ? array_map(static fn($r) => trim((string)($r->gst_per ?? '0')), $gstRates) : $standardGstValues;
|
||||
foreach ($standardGstValues as $sv) {
|
||||
if (!in_array($sv, $rawRates, true)) $rawRates[] = $sv;
|
||||
}
|
||||
?>
|
||||
<?php foreach ($rawRates as $gstValue): ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === (float) $cgst) ? 'selected' : '' ?>><?= esc($formatGstOptionLabel($gstValue)) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<label class="form-label">SGST</label>
|
||||
<select class="form-select" name="input_SGST" id="input_SGST">
|
||||
<?php if (! empty($gstRates)): ?>
|
||||
<?php foreach ($gstRates as $rate): ?>
|
||||
<?php $gstValue = trim((string) ($rate->gst_per ?? '0')); ?>
|
||||
<?php if ($gstValue === '') { $gstValue = '0'; } ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === (float) $sgst) ? 'selected' : '' ?>><?= esc($gstValue) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<?php foreach (['0', '2.5', '5', '6', '9', '12'] as $gstValue): ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === (float) $sgst) ? 'selected' : '' ?>><?= esc($gstValue) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($rawRates as $gstValue): ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === (float) $sgst) ? 'selected' : '' ?>><?= esc($formatGstOptionLabel($gstValue)) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -103,37 +103,34 @@
|
|||
<div class="col-md-2">
|
||||
<label class="form-label">CGST</label>
|
||||
<select class="form-select form-select-sm" name="input_CGST" id="input_CGST" onchange="calculate()">
|
||||
<?php if (! empty($gstRates)): ?>
|
||||
<?php foreach ($gstRates as $rate): ?>
|
||||
<?php $gstValue = (string) ($rate->gst_per ?? '0'); ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === 2.5) ? 'selected' : '' ?>><?= esc($gstValue) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<option value="0">0</option>
|
||||
<option value="2.5" selected>2.5</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="9">9</option>
|
||||
<option value="12">12</option>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
$formatGstLabel = static function($val) {
|
||||
$f = (float)$val;
|
||||
if ($f == 0.0) return '0% (Exempt)';
|
||||
if ($f == 2.5) return '2.5% (5% GST)';
|
||||
if ($f == 9.0) return '9.0% (18% GST)';
|
||||
if ($f == 20.0) return '20% (40% GST)';
|
||||
if ($f == 6.0) return '6.0% (12% Legacy)';
|
||||
if ($f == 14.0) return '14% (28% Legacy)';
|
||||
return $val . '%';
|
||||
};
|
||||
$stdRates = ['0', '2.5', '9', '20', '6', '14'];
|
||||
$pRates = !empty($gstRates) ? array_map(static fn($r) => trim((string)($r->gst_per ?? '0')), $gstRates) : $stdRates;
|
||||
foreach ($stdRates as $sr) {
|
||||
if (!in_array($sr, $pRates, true)) $pRates[] = $sr;
|
||||
}
|
||||
?>
|
||||
<?php foreach ($pRates as $gstValue): ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === 2.5) ? 'selected' : '' ?>><?= esc($formatGstLabel($gstValue)) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">SGST / IGST</label>
|
||||
<select class="form-select form-select-sm" name="input_SGST" id="input_SGST" onchange="calculate()">
|
||||
<?php if (! empty($gstRates)): ?>
|
||||
<?php foreach ($gstRates as $rate): ?>
|
||||
<?php $gstValue = (string) ($rate->gst_per ?? '0'); ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === 2.5) ? 'selected' : '' ?>><?= esc($gstValue) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<option value="0">0</option>
|
||||
<option value="2.5" selected>2.5</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="9">9</option>
|
||||
<option value="12">12</option>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($pRates as $gstValue): ?>
|
||||
<option value="<?= esc($gstValue) ?>" <?= ((float) $gstValue === 2.5) ? 'selected' : '' ?>><?= esc($formatGstLabel($gstValue)) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ $showHeader = !empty($showHeader);
|
|||
<th class="text-end">Tax.Amt.28%</th>
|
||||
<th class="text-end">CGST 14%</th>
|
||||
<th class="text-end">SGST 14%</th>
|
||||
<th class="text-end">Tax.Amt.40%</th>
|
||||
<th class="text-end">CGST 20%</th>
|
||||
<th class="text-end">SGST 20%</th>
|
||||
<th class="text-end">Tax.Amt.0%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -54,6 +57,9 @@ $showHeader = !empty($showHeader);
|
|||
<td class="text-end"><?= esc(number_format((float) ($row['sale_28_amount'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['cgst_14'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['sgst_14'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['sale_40_amount'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['cgst_20'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['sgst_20'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['sale_0_amount'] ?? 0), 2)) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ $showHeader = !empty($showHeader);
|
|||
<th class="text-end">Tax.Amt.28%</th>
|
||||
<th class="text-end">CGST 14%</th>
|
||||
<th class="text-end">SGST 14%</th>
|
||||
<th class="text-end">Tax.Amt.40%</th>
|
||||
<th class="text-end">CGST 20%</th>
|
||||
<th class="text-end">SGST 20%</th>
|
||||
<th class="text-end">Tax.Amt.0%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -58,6 +61,9 @@ $showHeader = !empty($showHeader);
|
|||
<td class="text-end"><?= esc(number_format((float) ($row['sale_28_amount'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['cgst_14'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['sgst_14'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['sale_40_amount'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['cgst_20'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['sgst_20'] ?? 0), 2)) ?></td>
|
||||
<td class="text-end"><?= esc(number_format((float) ($row['sale_0_amount'] ?? 0), 2)) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
|
|
|||
|
|
@ -4047,7 +4047,7 @@ function PurchaseView({ store, notify }) {
|
|||
const [isSearchingMeds, setIsSearchingMeds] = useState(false);
|
||||
const [showMasterModal, setShowMasterModal] = useState(false);
|
||||
const [masterTargetRow, setMasterTargetRow] = useState(null);
|
||||
const [supportData, setSupportData] = useState({ formulations: [], companies: [], gst_rates: [0, 5, 12, 18, 28], schedules: [] });
|
||||
const [supportData, setSupportData] = useState({ formulations: [], companies: [], gst_rates: [0, 5, 18, 40, 12, 28], schedules: [] });
|
||||
const [isSavingMaster, setIsSavingMaster] = useState(false);
|
||||
const [masterForm, setMasterForm] = useState({
|
||||
item_name: '',
|
||||
|
|
@ -4056,7 +4056,7 @@ function PurchaseView({ store, notify }) {
|
|||
units_per_pack: 10,
|
||||
packing: '10',
|
||||
hsn_code: '3004',
|
||||
gst_rate: 12,
|
||||
gst_rate: 5,
|
||||
drug_schedule: 'Schedule H',
|
||||
company_name: '',
|
||||
min_reorder_level: 10
|
||||
|
|
@ -5819,11 +5819,12 @@ function PurchaseView({ store, notify }) {
|
|||
handleItemFormChange('sgst_pct', val);
|
||||
}}
|
||||
>
|
||||
<option value="0">0%</option>
|
||||
<option value="2.5">2.5%</option>
|
||||
<option value="6">6.0%</option>
|
||||
<option value="9">9.0%</option>
|
||||
<option value="14">14.0%</option>
|
||||
<option value="0">0% (Nil / Exempt)</option>
|
||||
<option value="2.5">2.5% (5% GST)</option>
|
||||
<option value="9">9.0% (18% GST)</option>
|
||||
<option value="20">20.0% (40% GST)</option>
|
||||
<option value="6">6.0% (12% Legacy)</option>
|
||||
<option value="14">14.0% (28% Legacy)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="col-md-2 col-6">
|
||||
|
|
@ -5833,11 +5834,12 @@ function PurchaseView({ store, notify }) {
|
|||
value={itemForm.sgst_pct}
|
||||
onChange={(e) => handleItemFormChange('sgst_pct', parseFloat(e.target.value) || 0)}
|
||||
>
|
||||
<option value="0">0%</option>
|
||||
<option value="2.5">2.5%</option>
|
||||
<option value="6">6.0%</option>
|
||||
<option value="9">9.0%</option>
|
||||
<option value="14">14.0%</option>
|
||||
<option value="0">0% (Nil / Exempt)</option>
|
||||
<option value="2.5">2.5% (5% GST)</option>
|
||||
<option value="9">9.0% (18% GST)</option>
|
||||
<option value="20">20.0% (40% GST)</option>
|
||||
<option value="6">6.0% (12% Legacy)</option>
|
||||
<option value="14">14.0% (28% Legacy)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="col-md-2 col-6">
|
||||
|
|
@ -7270,9 +7272,12 @@ function PurchaseView({ store, notify }) {
|
|||
value={masterForm.gst_rate}
|
||||
onChange={(e) => setMasterForm({ ...masterForm, gst_rate: Number(e.target.value) })}
|
||||
>
|
||||
{(supportData.gst_rates || [0, 5, 12, 18, 28]).map((g, idx) => (
|
||||
<option key={idx} value={g}>{g}% GST</option>
|
||||
))}
|
||||
<option value="0">0% (Nil / Exempt)</option>
|
||||
<option value="5">5% (Common / Basic Services)</option>
|
||||
<option value="18">18% (Standard - Most Products)</option>
|
||||
<option value="40">40% (Demerit / Sin Tax)</option>
|
||||
<option value="12">12% (Legacy Medicine Slab)</option>
|
||||
<option value="28">28% (Legacy High Slab)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
|
|
@ -7684,11 +7689,12 @@ function PurchaseView({ store, notify }) {
|
|||
setPoCreateForm({ ...poCreateForm, items });
|
||||
}}
|
||||
>
|
||||
<option value="0">0%</option>
|
||||
<option value="0">0% (Exempt)</option>
|
||||
<option value="5">5%</option>
|
||||
<option value="12">12%</option>
|
||||
<option value="18">18%</option>
|
||||
<option value="28">28%</option>
|
||||
<option value="40">40%</option>
|
||||
<option value="12">12% (Legacy)</option>
|
||||
<option value="28">28% (Legacy)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td className="text-end fw-bold">
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user