Compare commits

...

3 Commits

Author SHA1 Message Date
andriux1990
b64a93e483 Merging the postRequisitionComplete and complete functions 2025-01-18 20:58:26 -06:00
andriux1990
7f073bce8f Requisition (transfers) and payment methods in Receivings 2025-01-18 16:39:25 -06:00
jekkos
6ab72ce5c2 Fix for requisitions (#4147) 2025-01-15 23:47:32 +01:00
5 changed files with 673 additions and 103 deletions

View File

@@ -213,10 +213,13 @@ class Receivings extends Secure_Controller
$price = parse_decimals($this->request->getPost('price'));
$quantity = parse_quantity($this->request->getPost('quantity'));
$discount = parse_decimals($this->request->getPost('discount'));
$raw_receiving_quantity = parse_quantity($this->request->getPost('receiving_quantity'));
$description = $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS); //TODO: Duplicated code
$serialnumber = $this->request->getPost('serialnumber', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? '';
$price = filter_var($price, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$quantity = filter_var($quantity, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$discount_type = $this->request->getPost('discount_type', FILTER_SANITIZE_NUMBER_INT);
$discount = $discount_type
? parse_quantity(filter_var($this->request->getPost('discount'), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION))
@@ -263,6 +266,7 @@ class Receivings extends Secure_Controller
$data['selected_supplier_name'] = !empty($receiving_info['supplier_id']) ? $receiving_info['company_name'] : '';
$data['selected_supplier_id'] = $receiving_info['supplier_id'];
$data['receiving_info'] = $receiving_info;
$balance_due = round($receiving_info['amount_due'] - $receiving_info['amount_tendered'] + $receiving_info['cash_refund'], totals_decimals(), PHP_ROUND_HALF_UP);
echo view('receivings/form', $data);
}
@@ -324,22 +328,26 @@ class Receivings extends Secure_Controller
*/
public function postComplete(): void
{
$amount_tendered = parse_decimals($this->request->getPost('amount_tendered'));
$data = [];
$data['cart'] = $this->receiving_lib->get_cart();
$data['total'] = $this->receiving_lib->get_total();
$data['transaction_time'] = to_datetime(time());
$data['transaction_time'] = date('Y-m-d H:i:s'); // Fecha y hora actuales
$data['mode'] = $this->receiving_lib->get_mode();
$data['comment'] = $this->receiving_lib->get_comment();
$data['reference'] = $this->receiving_lib->get_reference();
$data['term_days'] = $this->receiving_lib->get_term_days();
$data['payment_type'] = $this->request->getPost('payment_type', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$data['payments'] = $this->receiving_lib->get_payments(); // Obtener pagos del carrito
$data['show_stock_locations'] = $this->stock_location->show_locations('receivings');
$data['stock_location'] = $this->receiving_lib->get_stock_source();
if($this->request->getPost('amount_tendered') != null)
{
$data['amount_tendered'] = parse_decimals($this->request->getPost('amount_tendered'));
$data['amount_change'] = to_currency($data['amount_tendered'] - $data['total']);
if ($this->request->getPost('amount_tendered') != null) {
$data['amount_tendered'] = filter_var($amount_tendered, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$data['amount_change'] = $data['amount_tendered'] - $data['total'];
} else {
$data['amount_change'] = 0;
}
$employee_id = $this->employee->get_logged_in_employee_info()->person_id;
@@ -347,40 +355,62 @@ class Receivings extends Secure_Controller
$data['employee'] = $employee_info->first_name . ' ' . $employee_info->last_name;
$supplier_id = $this->receiving_lib->get_supplier();
if($supplier_id != -1)
{
if ($supplier_id != -1) {
$supplier_info = $this->supplier->get_info($supplier_id);
$data['supplier'] = $supplier_info->company_name; //TODO: duplicated code
$data['supplier'] = $supplier_info->company_name;
$data['first_name'] = $supplier_info->first_name;
$data['last_name'] = $supplier_info->last_name;
$data['supplier_email'] = $supplier_info->email;
$data['supplier_address'] = $supplier_info->address_1;
if(!empty($supplier_info->zip) or !empty($supplier_info->city))
{
if (!empty($supplier_info->zip) || !empty($supplier_info->city)) {
$data['supplier_location'] = $supplier_info->zip . ' ' . $supplier_info->city;
}
else
{
} else {
$data['supplier_location'] = '';
}
}
//SAVE receiving to database
$data['receiving_id'] = 'RECV ' . $this->receiving->save_value($data['cart'], $supplier_id, $employee_id, $data['comment'], $data['reference'], $data['payment_type'], $data['stock_location']);
// Guardar el registro de compra en la base de datos
$receiving_id = $this->receiving->save_value(
$data['cart'],
$supplier_id,
$employee_id,
$data['comment'],
$data['reference'],
$data['term_days'],
$data['payment_type']
);
if($data['receiving_id'] == 'RECV -1')
{
if ($receiving_id == -1) {
$data['error_message'] = lang('Receivings.transaction_failed');
}
else
{
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['receiving_id']);
} else {
$data['receiving_id'] = $receiving_id;
// Calcular el cambio (cash_refund)
$total_payments = array_sum(array_column($data['payments'], 'payment_amount'));
$cash_refund = max(0, $total_payments - $data['total']);
// Guardar los pagos en la base de datos
foreach ($data['payments'] as $payment) {
$this->receiving->save_payment([
'receiving_id' => $receiving_id, // Utiliza el ID generado
'payment_type' => $payment['payment_type'],
'payment_amount' => $payment['payment_amount'],
'cash_refund' => ($payment['payment_type'] === lang('Sales.cash')) ? $cash_refund : 0,
'employee_id' => $employee_id,
'payment_time' => $data['transaction_time'], // Fecha y hora actuales
]);
}
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($receiving_id);
}
$data['print_after_sale'] = $this->receiving_lib->is_print_after_sale();
echo view("receivings/receipt",$data);
echo view("receivings/receipt", $data);
// Limpiar pagos y otros datos
$this->receiving_lib->clear_payments(); // Limpia los pagos
$this->receiving_lib->clear_all();
}
@@ -392,23 +422,58 @@ class Receivings extends Secure_Controller
*/
public function postRequisitionComplete(): void
{
if($this->receiving_lib->get_stock_source() != $this->receiving_lib->get_stock_destination())
{
foreach($this->receiving_lib->get_cart() as $item)
{
$this->receiving_lib->delete_item($item['line']);
$this->receiving_lib->add_item($item['item_id'], $item['quantity'], $this->receiving_lib->get_stock_destination(), $item['discount_type']);
$this->receiving_lib->add_item($item['item_id'], -$item['quantity'], $this->receiving_lib->get_stock_source(), $item['discount_type']);
}
$data = [];
$this->postComplete();
}
else
{
$data['error'] = lang('Receivings.error_requisition');
// Check if stock locations are different
if ($this->receiving_lib->get_stock_source() != $this->receiving_lib->get_stock_destination()) {
// Process items in the cart
foreach ($this->receiving_lib->get_cart() as $item) {
$this->receiving_lib->delete_item($item['line']);
$this->receiving_lib->add_item($item['item_id'], $item['quantity'], $this->receiving_lib->get_stock_destination(), $item['discount_type']);
$this->receiving_lib->add_item($item['item_id'], -$item['quantity'], $this->receiving_lib->get_stock_source(), $item['discount_type']);
}
$this->_reload($data); //TODO: Hungarian notation
}
// Prepare data to complete the requisition
$data['cart'] = $this->receiving_lib->get_cart();
$data['total'] = $this->receiving_lib->get_total();
$data['transaction_time'] = to_datetime(time());
$data['mode'] = $this->receiving_lib->get_mode();
$data['comment'] = $this->receiving_lib->get_comment();
$data['term_days'] = $this->receiving_lib->get_term_days();
$data['reference'] = $this->receiving_lib->get_reference();
$data['show_stock_locations'] = $this->stock_location->show_locations('receivings');
$data['stock_location_source'] = $this->receiving_lib->get_stock_source();
$data['stock_location_destination'] = $this->receiving_lib->get_stock_destination();
$employee_id = $this->employee->get_logged_in_employee_info()->person_id;
$employee_info = $this->employee->get_info($employee_id);
$data['employee'] = $employee_info->first_name . ' ' . $employee_info->last_name;
// Save the requisition in the database
$data['receiving_id'] = 'REQ ' . $this->receiving->save_requisition(
$data['cart'],
$employee_id,
$data['comment'],
$data['reference'],
$data['stock_location_source'],
$data['stock_location_destination']
);
if ($data['receiving_id'] == 'REQ -1') {
$data['error_message'] = lang('Receivings.transaction_failed');
} else {
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['receiving_id']);
}
$data['print_after_sale'] = $this->receiving_lib->is_print_after_sale();
echo view("receivings/receipt", $data);
$this->receiving_lib->clear_all();
} else {
$data['error'] = lang('Receivings.error_requisition');
$this->_reload($data);
}
}
/**
@@ -464,7 +529,7 @@ class Receivings extends Secure_Controller
* @param array $data
* @return void
*/
private function _reload(array $data = []): void //TODO: Hungarian notation
private function _reload(array $data = []): void
{
$data['cart'] = $this->receiving_lib->get_cart();
$data['modes'] = ['receive' => lang('Receivings.receiving'), 'return' => lang('Receivings.return')];
@@ -481,15 +546,26 @@ class Receivings extends Secure_Controller
$data['total'] = $this->receiving_lib->get_total();
$data['items_module_allowed'] = $this->employee->has_grant('items', $this->employee->get_logged_in_employee_info()->person_id);
$data['comment'] = $this->receiving_lib->get_comment();
$data['term_days'] = $this->receiving_lib->get_term_days();
$data['reference'] = $this->receiving_lib->get_reference();
$data['payment_options'] = $this->receiving->get_payment_options();
$data['selected_payment_type'] = $this->receiving_lib->get_payment_type();
$data['amount_due'] = $this->receiving_lib->get_total() - $this->receiving_lib->get_payments_total();
// Agregar pagos al arreglo de datos
$data['payments'] = $this->receiving_lib->get_payments();
// Inicializar tabindex
$data['tabindex'] = 0;
$supplier_id = $this->receiving_lib->get_supplier();
if($supplier_id != -1) //TODO: Duplicated Code... replace -1 with a constant
if($supplier_id != -1)
{
$supplier_info = $this->supplier->get_info($supplier_id);
$data['supplier'] = $supplier_info->company_name;
$data['avatar'] = $supplier_info->avatar;
$data['gender'] = $supplier_info->gender;
$data['first_name'] = $supplier_info->first_name;
$data['last_name'] = $supplier_info->last_name;
$data['supplier_email'] = $supplier_info->email;
@@ -512,9 +588,9 @@ class Receivings extends Secure_Controller
/**
* @throws ReflectionException
*/
public function save(int $receiving_id = -1): void //TODO: Replace -1 with a constant
public function save(int $receiving_id = -1): void
{
$newdate = $this->request->getPost('date', FILTER_SANITIZE_FULL_SPECIAL_CHARS); //TODO: newdate does not follow naming conventions
$newdate = $this->request->getPost('date', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$date_formatter = date_create_from_format($this->config['dateformat'] . ' ' . $this->config['timeformat'], $newdate);
$receiving_time = $date_formatter->format('Y-m-d H:i:s');
@@ -554,8 +630,77 @@ class Receivings extends Secure_Controller
*/
public function postCancelReceiving(): void
{
// Limpiar los pagos
$this->receiving_lib->clear_payments();
// Limpiar todos los datos relacionados con la transacción
$this->receiving_lib->clear_all();
$this->_reload(); //TODO: Hungarian Notation
// Recargar la vista
$this->_reload();
}
public function postAddPayment(): void
{
$data = [];
$payment_type = $this->request->getPost('payment_type', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
// Validar el tipo de pago
if ($payment_type !== lang('Sales.giftcard')) {
$rules = ['amount_tendered' => 'trim|required|decimal_locale'];
$messages = ['amount_tendered' => lang('Sales.must_enter_numeric')];
} else {
$rules = ['amount_tendered' => 'trim|required'];
$messages = ['amount_tendered' => lang('Sales.must_enter_numeric_giftcard')];
}
if (!$this->validate($rules, $messages)) {
$data['error'] = $payment_type === lang('Sales.giftcard')
? lang('Sales.must_enter_numeric_giftcard')
: lang('Sales.must_enter_numeric');
} else {
if ($payment_type === lang('Sales.giftcard')) {
$amount_tendered = parse_decimals($this->request->getPost('amount_tendered'));
$giftcard_num = filter_var($amount_tendered, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_ALLOW_FRACTION);
$payments = $this->receiving_lib->get_payments();
$payment_type = $payment_type . ':' . $giftcard_num;
$current_payments_with_giftcard = isset($payments[$payment_type]) ? $payments[$payment_type]['payment_amount'] : 0;
$giftcard = model(Giftcard::class);
$cur_giftcard_value = $giftcard->get_giftcard_value($giftcard_num);
if (($cur_giftcard_value - $current_payments_with_giftcard) <= 0) {
$data['error'] = lang('Giftcards.remaining_balance', [$giftcard_num, $cur_giftcard_value]);
} else {
$amount_tendered = min($this->receiving_lib->get_amount_due(), $cur_giftcard_value);
$this->receiving_lib->add_payment($payment_type, $amount_tendered);
}
} elseif ($payment_type === lang('Sales.cash')) {
$raw_amount_tendered = parse_decimals($this->request->getPost('amount_tendered'));
$amount_tendered = filter_var($raw_amount_tendered, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$this->receiving_lib->add_payment($payment_type, $amount_tendered);
} else {
$raw_amount_tendered = parse_decimals($this->request->getPost('amount_tendered'));
$amount_tendered = filter_var($raw_amount_tendered, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$this->receiving_lib->add_payment($payment_type, $amount_tendered);
}
}
$this->_reload($data);
}
/**
* Multiple Payments. Used in app/Views/sales/register.php
*
* @param string $payment_id
* @return void
* @noinspection PhpUnused
*/
public function getDeletePayment(string $payment_id): void
{
$this->receiving_lib->delete_payment($payment_id);
$this->_reload();
}
}

View File

@@ -6,11 +6,13 @@ use App\Models\Attribute;
use App\Models\Item;
use App\Models\Item_kit_items;
use App\Models\Item_quantity;
use App\Models\Enums\Rounding_mode;
use App\Models\Receiving;
use App\Models\Stock_location;
use CodeIgniter\Session\Session;
use Config\OSPOS;
use ReflectionException;
/**
* Receiving library
@@ -26,6 +28,7 @@ class Receiving_lib
private Receiving $receiving;
private Stock_location $stock_location;
private Session $session;
private array $config;
public function __construct()
{
@@ -35,6 +38,7 @@ class Receiving_lib
$this->item_quantity = model(Item_quantity::class);
$this->receiving = model(Receiving::class);
$this->stock_location = model(Stock_location::class);
$this->config = config(OSPOS::class)->settings;
$this->session = session();
}
@@ -194,6 +198,31 @@ class Receiving_lib
$this->session->remove('recv_reference');
}
/**
* @return string
*/
public function get_term_days(): string
{
return $this->session->get('recv_term_days') ?? '';
}
/**
* @param string $term_days
* @return void
*/
public function set_term_days(string $term_days): void
{
$this->session->set('recv_term_days', $term_days);
}
/**
* @return void
*/
public function clear_term_days(): void //TODO: This function verb is inconsistent from the others. Consider refactoring to remove_reference()
{
$this->session->remove('recv_term_days');
}
/**
* @return bool
*/
@@ -516,6 +545,7 @@ class Receiving_lib
$this->remove_supplier();
$this->clear_comment();
$this->clear_reference();
$this->clear_term_days();
}
/**
@@ -554,4 +584,200 @@ class Receiving_lib
return $total;
}
/**
* @param string $payment_type
* @return void
*/
public function set_payment_type(string $payment_type): void
{
$this->session->set('payment_type', $payment_type);
}
/**
* @return string|null
*/
public function get_payment_type(): ?string
{
return $this->session->get('payment_type');
}
public function get_total_due(): float
{
return $this->get_total() - $this->get_payments_total();
}
public function get_payments_total(): string
{
$subtotal = '0.0';
$cash_mode_eligible = CASH_MODE_TRUE;
foreach($this->get_payments() as $payments)
{
if(!$payments['cash_adjustment'])
{
$subtotal = bcadd($payments['payment_amount'], $subtotal);
}
if(lang('Sales.cash') != $payments['payment_type'] && lang('Sales.cash_adjustment') != $payments['payment_type'])
{
$cash_mode_eligible = CASH_MODE_FALSE;
}
}
if($cash_mode_eligible && $this->session->get('cash_rounding'))
{
$this->session->set('cash_mode', CASH_MODE_TRUE);
}
return $subtotal;
}
/**
* Multiple Payments
*/
public function get_payments(): array
{
if(!$this->session->get('sales_payments'))
{
$this->set_payments ([]);
}
return $this->session->get('sales_payments');
}
/**
* Multiple Payments
*/
public function set_payments(array $payments_data): void
{
$this->session->set('sales_payments', $payments_data);
}
/**
* Adds a new payment to the payments array or updates an existing one.
* It will also disable cash_mode if a non-qualifying payment type is added.
* @param string $payment_id
* @param string $payment_amount
* @param int $cash_adjustment
*/
public function add_payment(string $payment_id, string $payment_amount, int $cash_adjustment = CASH_ADJUSTMENT_FALSE): void
{
$payments = $this->get_payments();
if(isset($payments[$payment_id]))
{
//payment_method already exists, add to payment_amount
$payments[$payment_id]['payment_amount'] = bcadd($payments[$payment_id]['payment_amount'], $payment_amount);
}
else
{
//add to existing array
$payment = [
$payment_id => [
'payment_type' => $payment_id,
'payment_amount' => $payment_amount,
'cash_refund' => 0,
'cash_adjustment' => $cash_adjustment
]
];
$payments += $payment;
}
if($this->session->get('cash_mode'))
{
if($this->session->get('cash_rounding') && $payment_id != lang('Sales.cash') && $payment_id != lang('Sales.cash_adjustment'))
{
$this->session->set('cash_mode', CASH_MODE_FALSE);
}
}
$this->set_payments($payments);
}
/**
* Multiple Payments
*/
public function edit_payment(string $payment_id, float $payment_amount): bool
{
$payments = $this->get_payments();
if(isset($payments[$payment_id]))
{
$payments[$payment_id]['payment_type'] = $payment_id;
$payments[$payment_id]['payment_amount'] = $payment_amount;
$this->set_payments($payments);
return true;
}
return false;
}
/**
* Delete the selected payment from the payment array and if cash rounding is enabled
* and the payment type is one of the cash types then automatically delete the other
* @param string $payment_id
*/
public function delete_payment(string $payment_id): void
{
$payments = $this->get_payments();
$decoded_payment_id = urldecode($payment_id);
unset($payments[$decoded_payment_id]);
$cash_rounding = $this->reset_cash_rounding();
if($cash_rounding)
{
if($decoded_payment_id == lang('Sales.cash'))
{
unset($payments[lang('Sales.cash_adjustment')]);
}
if($decoded_payment_id == lang('Sales.cash_adjustment'))
{
unset($payments[lang('Sales.cash')]);
}
}
$this->set_payments($payments);
}
/**
* Determines if cash rounding should be a consideration for this site
* It also set resets the cash mode to disabled which will then be re-evaluated when
* retrieving payments.
*/
public function reset_cash_rounding(): int
{
$cash_rounding_code = $this->config['cash_rounding_code'];
if(cash_decimals() < totals_decimals() || $cash_rounding_code == Rounding_mode::HALF_FIVE)
{
$cash_rounding = 1;
}
else
{
$cash_rounding = 0;
}
$this->session->set('cash_rounding', $cash_rounding);
$this->session->set('cash_mode', CASH_MODE_FALSE);
return $cash_rounding;
}
/**
* @param string $total
* @return string
*/
public function check_for_cash_rounding(string $total): string
{
$cash_decimals = cash_decimals();
$cash_rounding_code = $this->config['cash_rounding_code'];
return Rounding_mode::round_number($cash_rounding_code, (float)$total, $cash_decimals);
}
public function clear_payments(): void
{
$this->set_payments([]);
}
}

View File

@@ -104,7 +104,7 @@ class Receiving extends Model
/**
* @throws ReflectionException
*/
public function save_value(array $items, int $supplier_id, int $employee_id, string $comment, string $reference, string $payment_type, int $receiving_id = NEW_ENTRY): int //TODO: $receiving_id gets overwritten before it's evaluated. It doesn't make sense to pass this here.
public function save_value(array $items, int $supplier_id, int $employee_id, string $comment, string $reference, string $term_days, string $payment_type, int $receiving_id = NEW_ENTRY): int //TODO: $receiving_id gets overwritten before it's evaluated. It doesn't make sense to pass this here.
{
$attribute = model(Attribute::class);
$inventory = model('Inventory');
@@ -123,7 +123,8 @@ class Receiving extends Model
'employee_id' => $employee_id,
'payment_type' => $payment_type,
'comment' => $comment,
'reference' => $reference
'reference' => $reference,
'term_days' => $term_days
];
//Run these queries as a transaction, we want to make sure we do all or nothing
@@ -187,7 +188,7 @@ class Receiving extends Model
$inventory->insert($inv_data, false);
$attribute->copy_attribute_links($item_data['item_id'], 'receiving_id', $receiving_id);
$supplier = $supplier->get_info($supplier_id); //TODO: supplier is never used after this.
// $supplier = $supplier->get_info($supplier_id); //TODO: supplier is never used after this.
}
$this->db->transComplete();
@@ -195,6 +196,153 @@ class Receiving extends Model
return $this->db->transStatus() ? $receiving_id : -1;
}
/**
* Save a requisition to the `ospos_receivings` and `ospos_receivings_items` tables
* and update stock quantities in the respective locations.
*
* @throws ReflectionException
*/
public function save_requisition(array $items, int $employee_id, string $comment, string $reference, int $stock_source, int $stock_destination): int
{
$inventory = model('Inventory');
$item_quantity_model = model(Item_quantity::class);
if (count($items) == 0) {
return -1; // No items to save
}
// Prepare the receiving data
$receivings_data = [
'receiving_time' => date('Y-m-d H:i:s'),
'employee_id' => $employee_id,
'comment' => $comment,
'reference' => $reference,
'total' => 0, // This will be updated later
'amount_change' => 0,
'amount_tendered' => 0,
'operation_type' => 'Requisition',
];
// Run these queries as a transaction
$this->db->transStart();
// Insert into `ospos_receivings`
$builder = $this->db->table('ospos_receivings');
$builder->insert($receivings_data);
$receiving_id = $this->db->insertID();
if (!$receiving_id) {
log_message('error', 'Failed to insert requisition header: ' . print_r($receivings_data, true));
$this->db->transRollback();
return -1;
}
// Insert items into `ospos_receivings_items`
$builder = $this->db->table('ospos_receivings_items');
$total_cost = 0;
foreach ($items as $item_data) {
$receivings_items_data = [
'receiving_id' => $receiving_id,
'item_id' => $item_data['item_id'],
'line' => $item_data['line'],
'description' => $item_data['description'] ?? '',
'serialnumber' => $item_data['serialnumber'] ?? '',
'quantity_purchased' => $item_data['quantity'],
'item_cost_price' => $item_data['price'],
'item_unit_price' => $item_data['price'],
'discount' => $item_data['discount'] ?? 0,
'discount_type' => $item_data['discount_type'] ?? 0,
'item_location' => $item_data['item_location'] ?? 1,
'receiving_quantity' => $item_data['receiving_quantity'] ?? 1,
];
$builder->insert($receivings_items_data);
if (!$this->db->affectedRows()) {
log_message('error', 'Failed to insert requisition item: ' . print_r($receivings_items_data, true));
$this->db->transRollback();
return -1;
}
// Calculate the total cost
$total_cost += ($item_data['price'] * $item_data['quantity']) - ($item_data['discount'] ?? 0);
// Update stock quantities
$item_id = $item_data['item_id'] > 0 ? $item_data['item_id'] : 0;
$quantity = $item_data['quantity'] > 0 ? $item_data['quantity'] : 0;
if ($item_id === 0 || $quantity === 0) {
continue; // Skip if item or quantity is invalid
}
// Subtract from stock at the source
$source_quantity = $item_quantity_model->get_item_quantity($item_id, $stock_source);
$item_quantity_model->save_value([
'quantity' => $source_quantity->quantity - $quantity,
'item_id' => $item_id,
'location_id' => $stock_source,
], $item_id, $stock_source);
// Add to stock at the destination
$destination_quantity = $item_quantity_model->get_item_quantity($item_id, $stock_destination);
$item_quantity_model->save_value([
'quantity' => $destination_quantity->quantity + $quantity,
'item_id' => $item_id,
'location_id' => $stock_destination,
], $item_id, $stock_destination);
// Register inventory for the outgoing location (only if not already registered)
$recv_remarks = 'REQ ' . $receiving_id;
$inv_data_source = [
'trans_date' => date('Y-m-d H:i:s'),
'trans_items' => $item_id,
'trans_user' => $employee_id,
'trans_location' => $stock_source,
'trans_comment' => $recv_remarks . ' OUT',
'trans_inventory' => -$quantity,
];
$existing_source = $inventory->where([
'trans_items' => $item_id,
'trans_location' => $stock_source,
'trans_comment' => $recv_remarks . ' OUT'
])->countAllResults();
if ($existing_source === 0) {
$inventory->insert($inv_data_source, false);
}
// Register inventory for the incoming location (only if not already registered)
$inv_data_destination = [
'trans_date' => date('Y-m-d H:i:s'),
'trans_items' => $item_id,
'trans_user' => $employee_id,
'trans_location' => $stock_destination,
'trans_comment' => $recv_remarks . ' IN',
'trans_inventory' => $quantity,
];
$existing_destination = $inventory->where([
'trans_items' => $item_id,
'trans_location' => $stock_destination,
'trans_comment' => $recv_remarks . ' IN'
])->countAllResults();
if ($existing_destination === 0) {
$inventory->insert($inv_data_destination, false);
}
}
// Update the total cost in ospos_receivings
$this->db->table('ospos_receivings')
->where('receiving_id', $receiving_id)
->update(['total' => $total_cost]);
if (!$this->db->transComplete()) {
log_message('error', 'Transaction failed for requisition: ' . print_r($receivings_data, true));
return -1;
}
return $receiving_id;
}
/**
* @throws ReflectionException
@@ -364,4 +512,9 @@ class Receiving extends Model
$this->db->query($sql);
}
public function save_payment(array $payment_data): bool
{
return $this->db->table('ospos_receivings_payments')->insert($payment_data);
}
}

View File

@@ -143,7 +143,7 @@
?>
<tr>
<td colspan="3" style='text-align:right;'><?= lang('Sales.amount_tendered') ?></td>
<td><div class="total-value"><?= to_currency($amount_tendered) ?></div></td>
<td><div class="total-value">0.00</div></td>
</tr>
<tr>

View File

@@ -155,77 +155,76 @@ if (isset($success))
<td><?= anchor("$controller_name/deleteItem/$line", '<span class="glyphicon glyphicon-trash"></span>') ?></td>
<td><?= esc($item['item_number']) ?></td>
<td style="text-align:center;">
<?= esc($item['name'] . ' '. implode(' ', [$item['attribute_values'], $item['attribute_dtvalues']])) ?><br /> <?= '[' . to_quantity_decimals($item['in_stock']) . ' in ' . $item['stock_name'] . ']' ?>
<?= esc($item['name'] . ' ' . implode(' ', [$item['attribute_values'], $item['attribute_dtvalues']])) ?><br />
<?= '[' . to_quantity_decimals($item['in_stock']) . ' in ' . $item['stock_name'] . ']' ?>
<?= form_hidden('location', (string)$item['item_location']) ?>
</td>
<?php
if ($items_module_allowed && $mode != 'requisition')
{
?>
<td><?= form_input ([
<?php if ($items_module_allowed && $mode != 'requisition') { ?>
<td><?= form_input([
'name' => 'price',
'class' => 'form-control input-sm',
'value' => to_currency_no_money($item['price']),
'value' => (string)to_currency_no_money($item['price']),
'onClick' => 'this.select();'
]) ?></td>
<?php
}
else
{
?>
<?php } else { ?>
<td>
<?= $item['price'] ?>
<?= form_hidden('price', to_currency_no_money($item['price'])) ?>
<?= (string)$item['price'] ?>
<?= form_hidden('price', (string)to_currency_no_money($item['price'])) ?>
</td>
<?php
}
?>
<?php } ?>
<td><?= form_input (['name' => 'quantity', 'class' => 'form-control input-sm', 'value' => to_quantity_decimals($item['quantity']),'onClick' => 'this.select();']) ?></td>
<td><?= form_input([
'name' => 'quantity',
'class' => 'form-control input-sm',
'value' => (string)to_quantity_decimals($item['quantity']),
'onClick' => 'this.select();'
]) ?></td>
<td><?= form_dropdown(
'receiving_quantity',
$item['receiving_quantity_choices'],
$item['receiving_quantity'],
['class' => 'form-control input-sm']
) ?></td>
'receiving_quantity',
$item['receiving_quantity_choices'],
(string)$item['receiving_quantity'],
['class' => 'form-control input-sm']
) ?></td>
<?php
if ($items_module_allowed && $mode != 'requisition')
{
?>
<?php if ($items_module_allowed && $mode != 'requisition') { ?>
<td>
<div class="input-group">
<?= form_input (['name' => 'discount', 'class' => 'form-control input-sm', 'value' => $item['discount_type'] ? to_currency_no_money($item['discount']) : to_decimals($item['discount']), 'onClick' => 'this.select();']) ?>
<span class="input-group-btn">
<?= form_checkbox ([
'id' => 'discount_toggle',
'name' => 'discount_toggle',
'value' => 1,
'data-toggle' => "toggle",
'data-size' => 'small',
'data-onstyle' => 'success',
'data-on' => '<b>' . $config['currency_symbol'] .'</b>',
'data-off' => '<b>%</b>',
'data-line' => $line,
'checked' => $item['discount_type'] == 1
<div class="input-group">
<?= form_input([
'name' => 'discount',
'class' => 'form-control input-sm',
'value' => (string)($item['discount_type'] ? to_currency_no_money($item['discount']) : to_decimals($item['discount'])),
'onClick' => 'this.select();'
]) ?>
</span>
</div>
</td>
<?php
}
else
{
?>
<td><?= $item['discount'] ?></td>
<?= form_hidden('discount', $item['discount']) ?>
<?php
}
?>
<span class="input-group-btn">
<?= form_checkbox([
'id' => 'discount_toggle',
'name' => 'discount_toggle',
'value' => 1,
'data-toggle' => "toggle",
'data-size' => 'small',
'data-onstyle' => 'success',
'data-on' => '<b>' . $config['currency_symbol'] . '</b>',
'data-off' => '<b>%</b>',
'data-line' => $line,
'checked' => $item['discount_type'] == 1
]) ?>
</span>
</div>
</td>
<?php } else { ?>
<td><?= (string)$item['discount'] ?></td>
<?= form_hidden('discount', (string)$item['discount']) ?>
<?php } ?>
<td>
<?= to_currency(($item['discount_type'] == PERCENT) ? $item['price']*$item['quantity']*$item['receiving_quantity'] - $item['price'] * $item['quantity'] * $item['receiving_quantity'] * $item['discount'] / 100 : $item['price']*$item['quantity']*$item['receiving_quantity'] - $item['discount']) ?></td>
<td><a href="javascript:$('#<?= esc("cart_$line", 'js') ?>').submit();" title=<?= lang(ucfirst($controller_name) .'.update') ?> ><span class="glyphicon glyphicon-refresh"></span></a></td>
<?= to_currency(
($item['discount_type'] == PERCENT)
? $item['price'] * $item['quantity'] * $item['receiving_quantity'] - $item['price'] * $item['quantity'] * $item['receiving_quantity'] * $item['discount'] / 100
: $item['price'] * $item['quantity'] * $item['receiving_quantity'] - $item['discount']
) ?>
</td>
<td><a href="javascript:$('#<?= esc("cart_$line", 'js') ?>').submit();" title=<?= lang(ucfirst($controller_name) . '.update') ?>><span class="glyphicon glyphicon-refresh"></span></a></td>
</tr>
<tr>
<?php
@@ -375,6 +374,53 @@ if (isset($success))
</tr>
</table>
<?= form_open("$controller_name/addPayment", ['id' => 'add_payment_form', 'class' => 'form-horizontal']) ?>
<section class="mainContent">
<div class="formContainer">
<form action="">
<fieldset class="fieldInput">
<div class="dropdown">
<?= form_dropdown('payment_type', $payment_options, $selected_payment_type, ['id' => 'payment_types', 'class' => 'dropdown-toggle', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
</div>
<?= form_input (['name' => 'amount_tendered', 'id' => 'amount_tendered', 'class' => 'form-input', 'value' => to_currency_no_money($amount_due), 'size' => '5', 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']) ?>
<?= form_input (['name' => 'amount_tendered', 'id' => 'amount_tendered', 'class' => 'form-input', 'disabled' => true, 'value' => to_currency_no_money($amount_due), 'size' => '5', 'tabindex' => ++$tabindex]) ?>
<button type="submit" class="form-submit" id='add_payment_button' tabindex="<?= ++$tabindex ?>"><i class="bi bi-credit-card-fill"></i> Pagar</button>
</fieldset>
</form>
</div>
</section>
<?= form_close() ?>
<table class="sales_table_100" id="registersss">
<thead>
<tr>
<th style="width: 10%;"><?= lang('Common.delete') ?></th>
<th style="width: 60%;"><?= lang(ucfirst($controller_name) .'.payment_type') ?></th>
<th style="width: 20%;"><?= lang(ucfirst($controller_name) .'.payment_amount') ?></th>
</tr>
</thead>
<tbody id="payment_contents">
<?php
$payment_types = [];
foreach($payments as $payment_id => $payment)
{
$payment_types[] = $payment['payment_type'];
?>
<tr>
<td><?= anchor("$controller_name/deletePayment/$payment_id", '<span class="glyphicon glyphicon-trash"></span>') ?></td>
<td><?= esc($payment['payment_type']) ?></td>
<td style="text-align: right;"><?= to_currency($payment['payment_amount']) ?></td>
</tr>
<?php
}
$payment_types_string = implode(', ', $payment_types);
?>
</tbody>
</table>
<?php
if(count($cart) > 0)
{