1101 lines
44 KiB
PHP
1101 lines
44 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers;
|
|
use CodeIgniter\RESTful\ResourceController;
|
|
use App\Models\PolicyModel;
|
|
use App\Models\EnquiryModel;
|
|
use App\Models\QuotationModel;
|
|
use App\Models\InvoiceModel;
|
|
use App\Models\InvoiceItemModel;
|
|
use App\Models\InvoiceUtrModel;
|
|
use App\Models\PartnerAccountHistoryModel;
|
|
// use App\Models\AgentIncentiveFileModel;
|
|
use CodeIgniter\Database\Exceptions\DataException;
|
|
// use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
|
|
class InvoiceController extends ResourceController
|
|
{
|
|
protected $PolicyModel;
|
|
protected $QuotationModel;
|
|
protected $EnquiryModel;
|
|
protected $InvoiceModel;
|
|
protected $InvoiceItemModel;
|
|
protected $InvoiceUtrModel;
|
|
protected $PartnerAccountHistoryModel;
|
|
// protected $AgentIncentiveFileModel;
|
|
protected $db;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->PolicyModel = new PolicyModel();
|
|
$this->QuotationModel = new QuotationModel();
|
|
$this->EnquiryModel = new EnquiryModel();
|
|
$this->InvoiceModel = new InvoiceModel();
|
|
$this->InvoiceItemModel = new InvoiceItemModel();
|
|
$this->InvoiceUtrModel = new InvoiceUtrModel();
|
|
$this->PartnerAccountHistoryModel = new PartnerAccountHistoryModel();
|
|
// $this->AgentIncentiveFileModel = new AgentIncentiveFileModel();
|
|
$this->db = \Config\Database::connect();
|
|
}
|
|
|
|
public function invoiceList()
|
|
{
|
|
try {
|
|
|
|
$data = $this->InvoiceModel
|
|
->select('partner_invoice.*,
|
|
PB.name as broker_name,
|
|
pos.name as pos_name,
|
|
FORMAT(partner_invoice.invoice_amount, 2, "en_IN") AS invoice_amount_indian_format,
|
|
DATE_FORMAT(partner_invoice.invoice_date, "%d-%m-%Y") AS invoice_date_ui_format,
|
|
(
|
|
SELECT GROUP_CONCAT(pa.name ORDER BY pa.id SEPARATOR ", ")
|
|
FROM partner_agent pa
|
|
WHERE JSON_SEARCH(partner_invoice.agent_id, "one", CAST(pa.id AS CHAR)) IS NOT NULL
|
|
) AS partner_names,
|
|
(
|
|
SELECT GROUP_CONCAT(piu.utr_no ORDER BY piu.id SEPARATOR ", ")
|
|
FROM partner_invoice_utr piu
|
|
WHERE piu.invoice_id = partner_invoice.id
|
|
AND piu.is_active = 1
|
|
) AS utr_numbers,
|
|
partner_invoice.invoice_amount AS invoiced_amount,
|
|
(
|
|
COALESCE((
|
|
SELECT SUM(pah.paid_amount)
|
|
FROM partner_account_history pah
|
|
WHERE pah.invoice_id = partner_invoice.id
|
|
AND pah.is_active = 1
|
|
), 0.00)
|
|
+
|
|
COALESCE((
|
|
SELECT SUM(piu.amount)
|
|
FROM partner_invoice_utr piu
|
|
WHERE piu.invoice_id = partner_invoice.id
|
|
AND piu.is_active = 1
|
|
), 0.00)
|
|
) AS payout_amount,
|
|
(
|
|
partner_invoice.invoice_amount - (
|
|
COALESCE((
|
|
SELECT SUM(pah.paid_amount)
|
|
FROM partner_account_history pah
|
|
WHERE pah.invoice_id = partner_invoice.id
|
|
AND pah.is_active = 1
|
|
), 0.00)
|
|
+
|
|
COALESCE((
|
|
SELECT SUM(piu.amount)
|
|
FROM partner_invoice_utr piu
|
|
WHERE piu.invoice_id = partner_invoice.id
|
|
AND piu.is_active = 1
|
|
), 0.00)
|
|
)
|
|
) AS balance_amount',
|
|
false)
|
|
->join('partner_brokers PB', 'PB.id = partner_invoice.broker_id', 'left')
|
|
->join('partner_pos pos', 'pos.id = partner_invoice.pos_id', 'left')
|
|
->where('partner_invoice.is_active', 1)
|
|
->orderBy('partner_invoice.id', 'DESC')
|
|
->findAll();
|
|
|
|
return $this->respond(['status' => 'success', 'code' => 200,'data' => $data ], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function findInvoiceWithItems()
|
|
{
|
|
try {
|
|
$id = $this->request->getGet('id');
|
|
|
|
if (!$id) {
|
|
return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'ID is required'], 400);
|
|
}
|
|
|
|
$invoice = $this->InvoiceModel->where('id', $id)->first();
|
|
|
|
if (!$invoice) {
|
|
return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Invoice not found'], 404);
|
|
}
|
|
|
|
$items = $this->InvoiceItemModel->select('partner_invoice_items.* , pp.issued_date , pe.name as customer_name , pq.premium_amount')
|
|
->join('partner_policy pp','pp.id = partner_invoice_items.policy_id ', 'left')
|
|
->join('partner_enquiry pe','pe.id = pp.enquiry_id ', 'left')
|
|
->join('partner_quotation pq','pq.id = pp.quotation_id ', 'left')
|
|
->where('partner_invoice_items.invoice_id', $id)
|
|
->where('partner_invoice_items.is_active', 1)
|
|
->findAll();
|
|
|
|
$paymentHistory = $this->PartnerAccountHistoryModel
|
|
->where('invoice_id', $id)
|
|
->where('is_active', 1)
|
|
->orderBy('paid_date', 'DESC')
|
|
->orderBy('id', 'DESC')
|
|
->findAll();
|
|
|
|
$paidAmount = 0.00;
|
|
foreach ($paymentHistory as $payment) {
|
|
$paidAmount += (float) ($payment['paid_amount'] ?? 0);
|
|
}
|
|
|
|
$utrPaidAmount = (float) (
|
|
$this->InvoiceUtrModel
|
|
->selectSum('amount', 'total')
|
|
->where('invoice_id', $id)
|
|
->where('is_active', 1)
|
|
->first()['total'] ?? 0
|
|
);
|
|
|
|
$totalPaidAmount = $paidAmount + $utrPaidAmount;
|
|
$invoiceAmount = (float) ($invoice['invoice_amount'] ?? 0);
|
|
$balanceAmount = max($invoiceAmount - $totalPaidAmount, 0);
|
|
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'code' => 200,
|
|
'data' => [
|
|
'invoice' => $invoice,
|
|
'items' => $items,
|
|
'payment_history' => $paymentHistory,
|
|
'paid_amount' => $totalPaidAmount,
|
|
'balance_amount' => $balanceAmount
|
|
]
|
|
], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function createOrUpdateInvoice()
|
|
{
|
|
$this->db->transBegin();
|
|
|
|
try {
|
|
$input = $this->request->getJSON(true);
|
|
|
|
// Basic invoice data
|
|
$invoiceData = [
|
|
'invoice_amount' => $input['invoice_amount'] ?? 0,
|
|
'broker_id' => $input['broker_id'] ?? 0,
|
|
'agent_id' => json_encode($input['agent_id'] ?? []),
|
|
'pos_id' => $input['pos_id'] ?? 0,
|
|
'till_date' => $input['till_date'] ? date('Y-m-d', strtotime($input['till_date'])) : null,
|
|
'invoice_date' => $input['invoice_date'] ? date('Y-m-d', strtotime($input['invoice_date'])) : null,
|
|
'payout_status' => 1,
|
|
'is_active' => 1,
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
'updated_by' => $input['updated_by'] ?? 0
|
|
];
|
|
|
|
$invoiceId = $input['id'] ?? null;
|
|
|
|
if (!$invoiceId) {
|
|
|
|
// Generate invoice number only for CREATE
|
|
$invoiceData['invoice_no'] = $this->generateInvoiceNo($input['pos_id'] ?? 0);
|
|
|
|
$invoiceData['created_at'] = date('Y-m-d H:i:s');
|
|
$invoiceData['created_by'] = $input['created_by'] ?? 0;
|
|
|
|
$invoiceId = $this->InvoiceModel->insert($invoiceData);
|
|
|
|
if ($invoiceId === false) {
|
|
log_message('error', json_encode($this->InvoiceModel->errors()));
|
|
return $this->respond(['status' => 'failed', 'message' => 'Failed to create invoice', 'error' => json_encode($this->InvoiceModel->errors())], 500);
|
|
}
|
|
} else {
|
|
|
|
// Invoice number should NOT change on update
|
|
unset($invoiceData['invoice_no']);
|
|
|
|
$this->InvoiceModel->update($invoiceId, $invoiceData);
|
|
}
|
|
|
|
// Insert or update items
|
|
if (!empty($input['items']) && is_array($input['items'])) {
|
|
|
|
foreach ($input['items'] as $item) {
|
|
|
|
$itemData = [
|
|
'invoice_id' => $invoiceId,
|
|
'policy_id' => $item['policy_id'],
|
|
'policy_no' => $item['policy_no'],
|
|
'commission_amount' => $item['commission_amount'] ?? 0,
|
|
'is_active' => $item['is_active'] ?? 1,
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
'updated_by' => $input['updated_by'] ?? 0
|
|
];
|
|
|
|
// UPDATE (if id exists)
|
|
if (!empty($item['id'])) {
|
|
|
|
$this->InvoiceItemModel->update($item['id'], $itemData);
|
|
|
|
}else{ // INSERT (if id missing)
|
|
|
|
$itemData['created_at'] = date('Y-m-d H:i:s');
|
|
$itemData['created_by'] = $input['created_by'] ?? 0;
|
|
$this->InvoiceItemModel->insert($itemData);
|
|
|
|
//update pos_id to policy table
|
|
$this->PolicyModel->update($item['policy_id'], ['pos_id' => $input['pos_id'] ]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ($this->db->transStatus() === false) {
|
|
$this->db->transRollback();
|
|
throw new DataException("Transaction failed");
|
|
}
|
|
|
|
$this->db->transCommit();
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'code' => 200,
|
|
'data' => ['invoice_id' => $invoiceId]
|
|
], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
$this->db->transRollback();
|
|
return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
private function generateInvoiceNo($pos_id)
|
|
{
|
|
$year = date('Y');
|
|
$prefix = !empty($pos_id) & $pos_id != 0 ? "NIIB/$pos_id/$year/" : "MIG/$year/";
|
|
|
|
// Get last invoice of current year
|
|
$lastInvoice = $this->InvoiceModel
|
|
->select('invoice_no')
|
|
->like('invoice_no', $prefix, 'after')
|
|
->where('pos_id',$pos_id)
|
|
->orderBy('id', 'DESC')
|
|
->first();
|
|
|
|
if ($lastInvoice && isset($lastInvoice['invoice_no'])) {
|
|
// Extract numeric part
|
|
$lastNumber = intval(substr($lastInvoice['invoice_no'], -5));
|
|
$nextNumber = $lastNumber + 1;
|
|
} else {
|
|
$nextNumber = 1;
|
|
}
|
|
|
|
return $prefix . str_pad($nextNumber, 5, '0', STR_PAD_LEFT);
|
|
}
|
|
|
|
|
|
public function deleteInvoice()
|
|
{
|
|
try {
|
|
$id = $this->request->getGet('id');
|
|
|
|
if (!$id) {
|
|
return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'ID is required'], 400);
|
|
}
|
|
|
|
$this->InvoiceModel->update($id, ['is_active' => 0]);
|
|
$this->InvoiceItemModel->where('invoice_id', $id)->set(['is_active' => 0])->update();
|
|
|
|
return $this->respond(['status' => 'success', 'code' => 200, 'data' => 'Invoice deleted'], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function getCommissionRateList()
|
|
{
|
|
try {
|
|
|
|
$input = $this->request->getJSON(true);
|
|
|
|
if (empty($input['broker_id'])) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 400,
|
|
'message'=> 'broker_id is required'
|
|
], 400);
|
|
}
|
|
|
|
$invoice_id = isset($input['invoice_id']) ? $input['invoice_id'] : '';
|
|
|
|
// Build the main query
|
|
$query = $this->PolicyModel
|
|
->select('partner_policy.policy_number as policy_no, partner_policy.id as policy_id, partner_policy.issued_date, partner_policy.commission_amount, partner_policy.insured_name as customer_name, pe.agent_id ,pa.name as agent_name,pa.agent_code, partner_policy.premium_amount, pi.id as invoice_id, pi.invoice_no')
|
|
->join(
|
|
'partner_enquiry pe',
|
|
'pe.id = partner_policy.enquiry_id AND pe.broker_id = ' . (int)$input['broker_id'],
|
|
'left'
|
|
)
|
|
->join('partner_quotation pq', 'pq.id = partner_policy.quotation_id', 'left')
|
|
->join('partner_invoice_items pii', 'pii.policy_id = partner_policy.id', 'left')
|
|
->join('partner_invoice pi', 'pi.id = pii.invoice_id AND pi.is_active = 1', 'left')
|
|
->join('partner_agent pa', 'pa.id = pe.agent_id', 'left')
|
|
->where('partner_policy.is_active', 1)
|
|
->where('partner_policy.commission_amount > 0')
|
|
->where('partner_policy.is_data_accuracy_checked', 1)
|
|
->where('partner_policy.manager_id', $input['manager_id']);
|
|
|
|
// Apply agent_id filter (supports multiple agents)
|
|
if (!empty($input['agent_id'])) {
|
|
if (is_array($input['agent_id'])) {
|
|
$query->whereIn('pe.agent_id', $input['agent_id']);
|
|
} else {
|
|
$query->where('pe.agent_id', $input['agent_id']);
|
|
}
|
|
}
|
|
|
|
// Apply date range filters
|
|
if (!empty($input['from_date'])) {
|
|
$query->where('partner_policy.issued_date >=', date('Y-m-d', strtotime($input['from_date'])));
|
|
}
|
|
|
|
if (!empty($input['to_date'])) {
|
|
$query->where('partner_policy.issued_date <=', date('Y-m-d', strtotime($input['to_date'])));
|
|
}
|
|
|
|
// Apply POS filter if provided
|
|
if (!empty($input['pos_id'])) {
|
|
$query->where('partner_policy.pos_id', $input['pos_id']);
|
|
}
|
|
|
|
// Filter based on invoice_id or policies not yet invoiced
|
|
if (empty($invoice_id)) {
|
|
$query->where('pii.policy_id IS NULL');
|
|
} else {
|
|
$query->where('pi.id', $invoice_id);
|
|
}
|
|
|
|
$data = $query->findAll();
|
|
|
|
// Calculate total commission
|
|
$total_commission = 0;
|
|
foreach ($data as $policy) {
|
|
$total_commission += $policy['commission_amount'];
|
|
}
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'code' => 200,
|
|
'data' => $data,
|
|
'total_commission' => $total_commission,
|
|
'total_policies' => count($data)
|
|
], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 500,
|
|
'message'=> $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function getAgentUnusedCommissionList()
|
|
{
|
|
try {
|
|
|
|
$manager_id = $this->request->getGet('manager_id');
|
|
$broker_id = $this->request->getGet('broker_id');
|
|
|
|
if (empty($broker_id)) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 400,
|
|
'message'=> 'broker_id is required'
|
|
], 400);
|
|
}
|
|
|
|
$query = $this->PolicyModel
|
|
->select([
|
|
'pe.agent_id',
|
|
'pa.name as agent_name',
|
|
'SUM(partner_policy.commission_amount) as unused_commission_amount',
|
|
'COUNT(partner_policy.id) as total_policies'
|
|
])
|
|
->join(
|
|
'partner_enquiry pe',
|
|
'pe.id = partner_policy.enquiry_id AND pe.broker_id = ' . (int)$broker_id,
|
|
'left'
|
|
)
|
|
->join('partner_agent pa', 'pa.id = pe.agent_id', 'left')
|
|
->join('partner_invoice_items pii', 'pii.policy_id = partner_policy.id', 'left')
|
|
->join('partner_invoice pi', 'pi.id = pii.invoice_id AND pi.is_active = 1', 'left')
|
|
->where('partner_policy.is_active', 1)
|
|
->where('partner_policy.commission_amount >', 0)
|
|
->where('partner_policy.is_data_accuracy_checked', 1)
|
|
->where('partner_policy.manager_id', $manager_id)
|
|
->where('pii.policy_id IS NULL') // ❗ unused commission
|
|
->groupBy('pe.agent_id');
|
|
|
|
|
|
|
|
$data = $query->findAll();
|
|
|
|
// Grand total (optional but useful for FE)
|
|
$grand_total = 0;
|
|
foreach ($data as $row) {
|
|
$grand_total += (float)$row['unused_commission_amount'];
|
|
}
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'code' => 200,
|
|
'data' => $data,
|
|
'grand_total_unused_commission' => $grand_total,
|
|
'total_agents' => count($data)
|
|
], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 500,
|
|
'message'=> $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function addInvoicePayment()
|
|
{
|
|
$this->db->transBegin();
|
|
|
|
try {
|
|
$input = $this->request->getJSON(true);
|
|
|
|
$invoiceId = (int)($input['invoice_id'] ?? 0);
|
|
$paidAmount = (float)($input['paid_amount'] ?? 0);
|
|
$paidDateRaw = $input['paid_date'] ?? null;
|
|
|
|
if ($invoiceId <= 0 || $paidAmount <= 0 || empty($paidDateRaw)) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 400,
|
|
'message'=> 'invoice_id, paid_amount and paid_date are required'
|
|
], 400);
|
|
}
|
|
|
|
$invoice = $this->InvoiceModel
|
|
->where('id', $invoiceId)
|
|
->where('is_active', 1)
|
|
->first();
|
|
|
|
if (empty($invoice)) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 404,
|
|
'message'=> 'Invoice not found'
|
|
], 404);
|
|
}
|
|
|
|
$paidDateTs = strtotime($paidDateRaw);
|
|
if ($paidDateTs === false) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 400,
|
|
'message'=> 'Invalid paid_date format'
|
|
], 400);
|
|
}
|
|
$paidDate = date('Y-m-d', $paidDateTs);
|
|
|
|
$historyPaidAmount = (float) (
|
|
$this->PartnerAccountHistoryModel
|
|
->selectSum('paid_amount', 'total')
|
|
->where('invoice_id', $invoiceId)
|
|
->where('is_active', 1)
|
|
->first()['total'] ?? 0
|
|
);
|
|
|
|
$utrPaidAmount = (float) (
|
|
$this->InvoiceUtrModel
|
|
->selectSum('amount', 'total')
|
|
->where('invoice_id', $invoiceId)
|
|
->where('is_active', 1)
|
|
->first()['total'] ?? 0
|
|
);
|
|
|
|
$currentTotalPaid = $historyPaidAmount + $utrPaidAmount;
|
|
$invoiceAmount = (float) ($invoice['invoice_amount'] ?? 0);
|
|
$remainingBalance = max($invoiceAmount - $currentTotalPaid, 0);
|
|
|
|
if ($paidAmount > $remainingBalance) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 400,
|
|
'message'=> 'Paid amount exceeds invoice balance'
|
|
], 400);
|
|
}
|
|
|
|
$historyData = [
|
|
'invoice_id' => $invoiceId,
|
|
'paid_amount' => $paidAmount,
|
|
'paid_date' => $paidDate,
|
|
'is_active' => 1,
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
'created_by' => (int)($input['created_by'] ?? 0),
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
'updated_by' => (int)($input['updated_by'] ?? 0),
|
|
];
|
|
|
|
$historyId = $this->PartnerAccountHistoryModel->insert($historyData);
|
|
|
|
if ($historyId === false) {
|
|
$this->db->transRollback();
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 500,
|
|
'message'=> 'Failed to record payment',
|
|
'error' => $this->PartnerAccountHistoryModel->errors()
|
|
], 500);
|
|
}
|
|
|
|
$latestTotalPaid = $currentTotalPaid + $paidAmount;
|
|
$newBalance = max($invoiceAmount - $latestTotalPaid, 0);
|
|
$payoutStatus = $newBalance == 0.0 ? 2 : 1;
|
|
|
|
$this->InvoiceModel->update($invoiceId, [
|
|
'payout_status' => $payoutStatus,
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
'updated_by' => (int)($input['updated_by'] ?? 0),
|
|
]);
|
|
|
|
if ($this->db->transStatus() === false) {
|
|
$this->db->transRollback();
|
|
throw new DataException('Transaction failed');
|
|
}
|
|
|
|
$this->db->transCommit();
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'code' => 200,
|
|
'data' => [
|
|
'history_id' => $historyId,
|
|
'invoice_id' => $invoiceId,
|
|
'paid_amount' => $latestTotalPaid,
|
|
'balance_amount' => $newBalance
|
|
]
|
|
], 200);
|
|
} catch (\Exception $e) {
|
|
$this->db->transRollback();
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 500,
|
|
'message'=> $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
// public function bulkUploadCommission()
|
|
// {
|
|
// $this->db->transBegin();
|
|
// try {
|
|
// $input = $this->request->getJSON(true);
|
|
// if (!is_array($input)) {
|
|
// $input = [];
|
|
// }
|
|
|
|
// $post = $this->request->getPost();
|
|
// if (!is_array($post)) {
|
|
// $post = [];
|
|
// }
|
|
|
|
// $rows = $input['rows'] ?? [];
|
|
// $updatedBy = (int)($input['updated_by'] ?? ($post['created_by'] ?? 0));
|
|
|
|
// // Multipart flow: read excel on backend and store upload metadata.
|
|
// $file = $this->request->getFile('file_name');
|
|
// if ($file && $file->isValid()) {
|
|
// $month = date('Y-m-d');
|
|
// $uploadPath = WRITEPATH . 'uploads/agent/incentive_file/';
|
|
// if (!is_dir($uploadPath)) {
|
|
// mkdir($uploadPath, 0777, true);
|
|
// }
|
|
|
|
// $storedFileName = time() . '_' . $file->getRandomName();
|
|
// $file->move($uploadPath, $storedFileName);
|
|
|
|
// $this->AgentIncentiveFileModel->insert([
|
|
// 'incentive_month' => $month,
|
|
// 'incentive_file_name' => $storedFileName,
|
|
// 'file_type' => 'invoice',
|
|
// 'is_active' => 1,
|
|
// 'created_by' => $updatedBy > 0 ? $updatedBy : null,
|
|
// ], true);
|
|
|
|
// $spreadsheet = IOFactory::load($uploadPath . $storedFileName);
|
|
// $excelRows = $spreadsheet->getActiveSheet()->toArray(null, true, true, false);
|
|
|
|
// if (empty($excelRows)) {
|
|
// return $this->respond([
|
|
// 'status' => 'failed',
|
|
// 'code' => 400,
|
|
// 'message' => 'Uploaded file is empty',
|
|
// ], 400);
|
|
// }
|
|
|
|
// $headerRow = $excelRows[0] ?? [];
|
|
// $headerIndex = [];
|
|
// foreach ($headerRow as $idx => $headerValue) {
|
|
// $normalized = preg_replace('/[^a-z0-9]/', '', strtolower(trim((string)$headerValue)));
|
|
// if (!empty($normalized)) {
|
|
// $headerIndex[$normalized] = (int)$idx;
|
|
// }
|
|
// }
|
|
|
|
// $policyIdx = $headerIndex['policynumber'] ?? null;
|
|
// $invoiceIdx = $headerIndex['invoicenumber'] ?? null;
|
|
// $commissionIdx = $headerIndex['commission'] ?? ($headerIndex['commissionamount'] ?? null);
|
|
|
|
// if ($policyIdx === null || $commissionIdx === null) {
|
|
// return $this->respond([
|
|
// 'status' => 'failed',
|
|
// 'code' => 400,
|
|
// 'message' => 'Expected columns: Policy Number, Invoice Number, Commission or Commission Amount',
|
|
// ], 400);
|
|
// }
|
|
|
|
// $fallbackInvoiceNo = trim((string)($post['invoice_number'] ?? ''));
|
|
// $rows = [];
|
|
// foreach ($excelRows as $index => $row) {
|
|
// if ($index === 0) {
|
|
// continue;
|
|
// }
|
|
|
|
// $policyNo = trim((string)($row[$policyIdx] ?? ''));
|
|
// $invoiceNoFromFile = $invoiceIdx !== null ? trim((string)($row[$invoiceIdx] ?? '')) : '';
|
|
// $invoiceNo = $invoiceNoFromFile !== '' ? $invoiceNoFromFile : $fallbackInvoiceNo;
|
|
// $commissionRaw = trim((string)($row[$commissionIdx] ?? ''));
|
|
|
|
// if ($policyNo === '' && $invoiceNo === '' && $commissionRaw === '') {
|
|
// continue;
|
|
// }
|
|
|
|
// $commission = (float)str_replace(',', '', $commissionRaw);
|
|
// if ($policyNo === '' || $invoiceNo === '' || !is_numeric(str_replace(',', '', $commissionRaw))) {
|
|
// return $this->respond([
|
|
// 'status' => 'failed',
|
|
// 'code' => 400,
|
|
// 'message' => 'Invalid data at line ' . ($index + 1),
|
|
// ], 400);
|
|
// }
|
|
|
|
// $rows[] = [
|
|
// 'line_no' => $index + 1,
|
|
// 'policy_number' => $policyNo,
|
|
// 'invoice_no' => $invoiceNo,
|
|
// 'commission_amount' => $commission,
|
|
// ];
|
|
// }
|
|
// }
|
|
|
|
public function bulkUploadCommission()
|
|
{
|
|
$this->db->transBegin();
|
|
try {
|
|
$input = $this->request->getJSON(true);
|
|
$rows = $input['rows'] ?? [];
|
|
$updatedBy = (int)($input['updated_by'] ?? 0);
|
|
|
|
if (empty($rows) || !is_array($rows)) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 400,
|
|
'message' => 'rows is required',
|
|
], 400);
|
|
}
|
|
|
|
$mismatchRows = [];
|
|
$validRows = [];
|
|
$skippedRows = 0;
|
|
|
|
foreach ($rows as $row) {
|
|
$policyNo = trim((string)($row['policy_number'] ?? ''));
|
|
$invoiceNo = trim((string)($row['invoice_no'] ?? ''));
|
|
$commissionAmount = (float)($row['commission_amount'] ?? 0);
|
|
$lineNo = (int)($row['line_no'] ?? 0);
|
|
|
|
if ($policyNo === '' || $invoiceNo === '') {
|
|
$skippedRows++;
|
|
continue;
|
|
}
|
|
|
|
$record = $this->db->table('partner_invoice_items pii')
|
|
->select('
|
|
pii.id as item_id,
|
|
pii.invoice_id,
|
|
pii.policy_id,
|
|
pii.policy_no,
|
|
pi.invoice_no,
|
|
pi.agent_id as invoice_agent_json,
|
|
pe.agent_id as policy_agent_id
|
|
')
|
|
->join('partner_invoice pi', 'pi.id = pii.invoice_id', 'inner')
|
|
->join('partner_policy pp', 'pp.id = pii.policy_id', 'left')
|
|
->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left')
|
|
->where('pii.is_active', 1)
|
|
->where('pi.is_active', 1)
|
|
->where('pi.invoice_no', $invoiceNo)
|
|
->where('pii.policy_no', $policyNo)
|
|
->get()
|
|
->getRowArray();
|
|
|
|
if (empty($record)) {
|
|
$skippedRows++;
|
|
continue;
|
|
}
|
|
|
|
$invoiceAgentIds = $this->extractAgentIdsFromInvoice($record['invoice_agent_json'] ?? '');
|
|
$policyAgentId = isset($record['policy_agent_id']) ? (int)$record['policy_agent_id'] : 0;
|
|
$targetAgentId = !empty($invoiceAgentIds) ? (int)$invoiceAgentIds[0] : 0;
|
|
$isMismatch = $policyAgentId > 0 && !in_array($policyAgentId, $invoiceAgentIds, true);
|
|
|
|
if ($isMismatch) {
|
|
$mismatchRows[] = [
|
|
'line_no' => $lineNo,
|
|
'item_id' => (int)$record['item_id'],
|
|
'invoice_id' => (int)$record['invoice_id'],
|
|
'policy_id' => (int)$record['policy_id'],
|
|
'policy_number' => $policyNo,
|
|
'invoice_no' => $invoiceNo,
|
|
'commission_amount' => $commissionAmount,
|
|
'policy_agent_id' => $policyAgentId,
|
|
'target_agent_id' => $targetAgentId,
|
|
];
|
|
continue;
|
|
}
|
|
|
|
$validRows[] = [
|
|
'item_id' => (int)$record['item_id'],
|
|
'invoice_id' => (int)$record['invoice_id'],
|
|
'policy_id' => (int)$record['policy_id'],
|
|
'commission_amount' => $commissionAmount,
|
|
];
|
|
}
|
|
|
|
if (!empty($mismatchRows)) {
|
|
$this->ensureBulkUploadStagingTable();
|
|
$token = $this->generateProceedToken();
|
|
|
|
$this->db->table('invoice_bulk_upload_staging')->insert([
|
|
'proceed_token' => $token,
|
|
'payload_json' => json_encode([
|
|
'rows' => $rows,
|
|
'updated_by' => $updatedBy,
|
|
]),
|
|
'mismatch_json' => json_encode($mismatchRows),
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
'created_by' => $updatedBy,
|
|
'is_active' => 1,
|
|
]);
|
|
|
|
$this->db->transRollback();
|
|
return $this->respond([
|
|
'status' => 'partner_mismatch',
|
|
'code' => 200,
|
|
'message' => 'Partner mismatch detected',
|
|
'mismatch_count' => count($mismatchRows),
|
|
'mismatches' => $mismatchRows,
|
|
'proceed_token' => $token,
|
|
], 200);
|
|
}
|
|
|
|
$updatedCount = $this->applyBulkCommissionRows($validRows, $updatedBy);
|
|
|
|
if ($this->db->transStatus() === false) {
|
|
$this->db->transRollback();
|
|
throw new DataException('Transaction failed');
|
|
}
|
|
|
|
$this->db->transCommit();
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'code' => 200,
|
|
'message' => 'Bulk upload completed',
|
|
'updated_count' => $updatedCount,
|
|
'skipped_count' => $skippedRows,
|
|
], 200);
|
|
} catch (\Exception $e) {
|
|
$this->db->transRollback();
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 500,
|
|
'message' => $e->getMessage(),
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function bulkUploadCommissionProceed()
|
|
{
|
|
$this->db->transBegin();
|
|
try {
|
|
$input = $this->request->getJSON(true);
|
|
$proceedToken = trim((string)($input['proceed_token'] ?? ''));
|
|
$forceReassign = (int)($input['force_reassign_partner'] ?? 0);
|
|
$updatedBy = (int)($input['updated_by'] ?? 0);
|
|
|
|
if ($proceedToken === '' || $forceReassign !== 1) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 400,
|
|
'message' => 'proceed_token and force_reassign_partner=1 are required',
|
|
], 400);
|
|
}
|
|
|
|
$this->ensureBulkUploadStagingTable();
|
|
$staging = $this->db->table('invoice_bulk_upload_staging')
|
|
->where('proceed_token', $proceedToken)
|
|
->where('is_active', 1)
|
|
->get()
|
|
->getRowArray();
|
|
|
|
if (empty($staging)) {
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 404,
|
|
'message' => 'Invalid or expired proceed token',
|
|
], 404);
|
|
}
|
|
|
|
$payload = json_decode($staging['payload_json'] ?? '{}', true);
|
|
$rows = $payload['rows'] ?? [];
|
|
$mismatchRows = json_decode($staging['mismatch_json'] ?? '[]', true);
|
|
|
|
foreach ($mismatchRows as $mismatch) {
|
|
$policyId = (int)($mismatch['policy_id'] ?? 0);
|
|
$targetAgentId = (int)($mismatch['target_agent_id'] ?? 0);
|
|
if ($policyId <= 0 || $targetAgentId <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$policy = $this->PolicyModel->select('enquiry_id')->where('id', $policyId)->first();
|
|
if (!empty($policy['enquiry_id'])) {
|
|
$this->EnquiryModel->update((int)$policy['enquiry_id'], [
|
|
'agent_id' => $targetAgentId,
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
'updated_by' => $updatedBy,
|
|
]);
|
|
}
|
|
}
|
|
|
|
$finalRows = [];
|
|
foreach ($rows as $row) {
|
|
$policyNo = trim((string)($row['policy_number'] ?? ''));
|
|
$invoiceNo = trim((string)($row['invoice_no'] ?? ''));
|
|
$commissionAmount = (float)($row['commission_amount'] ?? 0);
|
|
if ($policyNo === '' || $invoiceNo === '') {
|
|
continue;
|
|
}
|
|
|
|
$record = $this->db->table('partner_invoice_items pii')
|
|
->select('pii.id as item_id, pii.invoice_id, pii.policy_id')
|
|
->join('partner_invoice pi', 'pi.id = pii.invoice_id', 'inner')
|
|
->where('pii.is_active', 1)
|
|
->where('pi.is_active', 1)
|
|
->where('pi.invoice_no', $invoiceNo)
|
|
->where('pii.policy_no', $policyNo)
|
|
->get()
|
|
->getRowArray();
|
|
|
|
if (empty($record)) {
|
|
continue;
|
|
}
|
|
|
|
$finalRows[] = [
|
|
'item_id' => (int)$record['item_id'],
|
|
'invoice_id' => (int)$record['invoice_id'],
|
|
'policy_id' => (int)$record['policy_id'],
|
|
'commission_amount' => $commissionAmount,
|
|
];
|
|
}
|
|
|
|
$updatedCount = $this->applyBulkCommissionRows($finalRows, $updatedBy);
|
|
|
|
$this->db->table('invoice_bulk_upload_staging')
|
|
->where('id', (int)$staging['id'])
|
|
->update([
|
|
'is_active' => 0,
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
'updated_by' => $updatedBy,
|
|
]);
|
|
|
|
if ($this->db->transStatus() === false) {
|
|
$this->db->transRollback();
|
|
throw new DataException('Transaction failed');
|
|
}
|
|
|
|
$this->db->transCommit();
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'code' => 200,
|
|
'message' => 'Bulk upload completed with partner reassignment',
|
|
'updated_count' => $updatedCount,
|
|
], 200);
|
|
} catch (\Exception $e) {
|
|
$this->db->transRollback();
|
|
return $this->respond([
|
|
'status' => 'failed',
|
|
'code' => 500,
|
|
'message' => $e->getMessage(),
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
private function applyBulkCommissionRows(array $rows, int $updatedBy): int
|
|
{
|
|
$updatedCount = 0;
|
|
foreach ($rows as $row) {
|
|
$itemId = (int)($row['item_id'] ?? 0);
|
|
$invoiceId = (int)($row['invoice_id'] ?? 0);
|
|
$policyId = (int)($row['policy_id'] ?? 0);
|
|
$commissionAmount = (float)($row['commission_amount'] ?? 0);
|
|
if ($itemId <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$affected = $this->db->table('partner_invoice_items')
|
|
->where('id', $itemId)
|
|
->where('invoice_id', $invoiceId)
|
|
->where('policy_id', $policyId)
|
|
->where('is_active', 1)
|
|
->update([
|
|
'commission_amount' => $commissionAmount,
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
'updated_by' => $updatedBy,
|
|
]);
|
|
|
|
if ($affected) {
|
|
$updatedCount++;
|
|
}
|
|
}
|
|
|
|
return $updatedCount;
|
|
}
|
|
|
|
private function extractAgentIdsFromInvoice($agentJson): array
|
|
{
|
|
if (is_array($agentJson)) {
|
|
return array_values(array_map('intval', $agentJson));
|
|
}
|
|
if ($agentJson === null || $agentJson === '') {
|
|
return [];
|
|
}
|
|
|
|
$decoded = json_decode((string)$agentJson, true);
|
|
if (is_array($decoded)) {
|
|
return array_values(array_map('intval', $decoded));
|
|
}
|
|
|
|
if (is_numeric($agentJson)) {
|
|
return [(int)$agentJson];
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
private function generateProceedToken(): string
|
|
{
|
|
return bin2hex(random_bytes(16));
|
|
}
|
|
|
|
private function ensureBulkUploadStagingTable(): void
|
|
{
|
|
$sql = "CREATE TABLE IF NOT EXISTS invoice_bulk_upload_staging (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
proceed_token VARCHAR(64) NOT NULL UNIQUE,
|
|
payload_json LONGTEXT NULL,
|
|
mismatch_json LONGTEXT NULL,
|
|
is_active TINYINT(1) NOT NULL DEFAULT 1,
|
|
created_at DATETIME NULL,
|
|
created_by INT NULL,
|
|
updated_at DATETIME NULL,
|
|
updated_by INT NULL
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
|
|
$this->db->query($sql);
|
|
}
|
|
|
|
|
|
// public function getCommissionRateList()
|
|
// {
|
|
// try {
|
|
|
|
// $input = $this->request->getJSON(true);
|
|
|
|
// if (empty($input['broker_id']) || empty($input['issued_date'])) {
|
|
// return $this->respond([ 'status' => 'failed', 'code' => 400, 'message'=> 'issued_date are required' ], 400);
|
|
// }
|
|
|
|
// $invoice_id = isset($input['invoice_id']) ? $input['invoice_id'] : '';
|
|
|
|
|
|
// $data_previous = $this->PolicyModel
|
|
// ->select('partner_policy.policy_number as policy_no,partner_policy.id as policy_id , partner_policy.issued_date, partner_policy.commission_amount, pe.name as customer_name , pq.premium_amount')
|
|
// ->join(
|
|
// 'partner_enquiry pe',
|
|
// 'pe.id = partner_policy.enquiry_id AND pe.broker_id = ' . (int)$input['broker_id'],
|
|
// 'left'
|
|
// )
|
|
// ->join('partner_quotation pq','pq.id = partner_policy.quotation_id ', 'left')
|
|
// // ->where('partner_policy.pos_id', $input['pos_id'])
|
|
// ->where('partner_policy.issued_date <=', date('Y-m-d', strtotime($input['issued_date'])))
|
|
// ->where('partner_policy.is_active', 1)
|
|
// ->where('partner_policy.is_data_accuracy_checked', 1)
|
|
// ->findAll();
|
|
|
|
|
|
// $query = $this->PolicyModel
|
|
// ->select('partner_policy.policy_number as policy_no, partner_policy.id as policy_id, partner_policy.issued_date, partner_policy.commission_amount, pe.name as customer_name, pq.premium_amount, pi.id as invoice_id, pi.invoice_no')
|
|
// ->join(
|
|
// 'partner_enquiry pe',
|
|
// 'pe.id = partner_policy.enquiry_id AND pe.broker_id = ' . (int)$input['broker_id'],
|
|
// 'left'
|
|
// )
|
|
// ->join('partner_quotation pq','pq.id = partner_policy.quotation_id ', 'left')
|
|
// ->join('partner_invoice_items pii', 'pii.policy_id = partner_policy.id', 'left' )
|
|
// ->join('partner_invoice pi', 'pi.id = pii.invoice_id AND pi.is_active = 1', 'left')
|
|
// // ->where('partner_policy.pos_id', $input['pos_id'])
|
|
// ->where('partner_policy.issued_date <=', date('Y-m-d', strtotime($input['issued_date'])))
|
|
// ->where('partner_policy.is_active', 1)
|
|
// ->where('partner_policy.commission_amount > 0')
|
|
// ->where('partner_policy.is_data_accuracy_checked', 1);
|
|
// if (empty($invoice_id)) {
|
|
// $query->where('pii.policy_id IS NULL');
|
|
// } else {
|
|
// $query->where('pi.id', $invoice_id);
|
|
// }
|
|
|
|
// $data = $query->findAll();
|
|
|
|
// return $this->respond([
|
|
// 'status' => 'success',
|
|
// 'code' => 200,
|
|
// 'previous' => $data_previous,
|
|
// 'data' => $data
|
|
// ], 200);
|
|
|
|
// } catch (\Exception $e) {
|
|
// return $this->respond([
|
|
// 'status' => 'failed',
|
|
// 'code' => 500,
|
|
// 'message'=> $e->getMessage()
|
|
// ], 500);
|
|
// }
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|