mirror of
https://gitlab.com/signalytic/client-external/streamline/streamline-emr.git
synced 2026-09-11 18:51:31 +00:00
370 lines
17 KiB
PHP
Executable File
370 lines
17 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Modules\Stores\Services;
|
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
|
use Streamline\Models\ItemBatchWatcher;
|
|
use Streamline\Models\OpticalStockReconciliation;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Streamline\Models\BatchConsumptionTracking;
|
|
use Streamline\Models\IncomingWardChart;
|
|
use Streamline\Models\StockReconciliationReason;
|
|
use Streamline\Models\ReconilicationReason;
|
|
use Streamline\Models\WardTreatmentBatchDispensation;
|
|
use Streamline\Models\Dental;
|
|
use Streamline\Models\Drug;
|
|
use Streamline\Models\DrugForm;
|
|
use Streamline\Models\GeneralForm;
|
|
use Streamline\Models\Lab;
|
|
use Streamline\Models\LabForm;
|
|
use Streamline\Models\Radiology;
|
|
use Streamline\Models\Sundry;
|
|
|
|
class StoresItemService {
|
|
//function to get form name based on item type
|
|
public function get_item_form_name($item_id, $item_type){
|
|
switch($item_type)
|
|
{
|
|
case 1:
|
|
//get drug item form
|
|
$form_id = Drug::find($item_id)->form_id;
|
|
$form_name = DrugForm::find($form_id)->name??'';
|
|
return $form_name;
|
|
break;
|
|
case 2:
|
|
//get sundry item form
|
|
$form_id = Sundry::find($item_id)->form_id;
|
|
$form_name = GeneralForm::find($form_id)->name??'';
|
|
return $form_name;
|
|
break;
|
|
case 3:
|
|
//get dental item form
|
|
$form_name='';
|
|
return $form_name;
|
|
break;
|
|
case 4:
|
|
//get radiology item form
|
|
$form_id = Radiology::find($item_id)->form_id;
|
|
$form_name = GeneralForm::find($form_id)->name??'';
|
|
return $form_name;
|
|
break;
|
|
case 5:
|
|
//get labs item form
|
|
$form_id = Lab::find($item_id)->form_id??'';
|
|
$form_name = LabForm::find($form_id)->name??'';
|
|
return $form_name;
|
|
break;
|
|
case 6:
|
|
//get general_item item form
|
|
$form_name='';
|
|
return $form_name;
|
|
break;
|
|
case 7:
|
|
//get optical item form
|
|
$form_name='';
|
|
return $form_name;
|
|
break;
|
|
}
|
|
}
|
|
public function find_item_batch_watcher($batch_item_id, $selected_columns): array|object|null
|
|
{
|
|
return ItemBatchWatcher::select($selected_columns)->find($batch_item_id);
|
|
}
|
|
public function move_item_between_sections($item_batch_watcher, $quantity_to_move, $other_stock)
|
|
{
|
|
$item_batch_watcher->store_stock -= $quantity_to_move;
|
|
$item_batch_watcher->{$other_stock} =$item_batch_watcher->{$other_stock} + $quantity_to_move;
|
|
$item_batch_watcher->save();
|
|
}
|
|
public function move_next_available_item($item_type, $item_id,$column, $selected_columns, $quantity_to_move,$other_stock): array|object|null
|
|
{
|
|
|
|
if (batch_tracking_method() == "FIFO") {
|
|
$random_batch_next = ItemBatchWatcher::where(['item_id' => $item_id, 'item_type' => $item_type])->where("{$column}", '>', 0)->orderBy('id', 'asc')->select($selected_columns)->first();;
|
|
}
|
|
elseif (batch_tracking_method() == "FEFO") {
|
|
$random_batch_next = ItemBatchWatcher::where(['item_id' => $item_id, 'item_type' => $item_type])->where("{$column}", '>', 0)->orderBy(DB::raw('ABS(DATEDIFF(expiry_date, NOW()))'))->select($selected_columns)->first();;
|
|
}
|
|
if ($random_batch_next) {
|
|
$random_batch_next->store_stock -= $quantity_to_move;
|
|
$random_batch_next->{$other_stock} += $quantity_to_move;
|
|
$random_batch_next->save();
|
|
return $random_batch_next;
|
|
}
|
|
return false;
|
|
}
|
|
public function move_batch_item_from_store_to_other_sections($item_type, $item_id, $batch_item_id, $quantity_to_move, $requisition_id,$item_name_table,$move_to,$selected_columns,$other_stock)
|
|
{
|
|
$item_batch_watcher = $this->find_item_batch_watcher($batch_item_id,$selected_columns);
|
|
$batch_number = "";
|
|
if ($item_batch_watcher) {
|
|
$this->move_item_between_sections($item_batch_watcher, $quantity_to_move, $other_stock);
|
|
$batch_number = $item_batch_watcher->batch_number;
|
|
} else{
|
|
//reduce the next one in line that has enough store stock.
|
|
$batch_details= $this->move_next_available_item($item_type, $item_id,'store_stock', $selected_columns, $quantity_to_move,$other_stock);
|
|
if($batch_details){
|
|
$batch_number = $batch_details->batch_number;
|
|
}
|
|
}
|
|
record_store_stock_movement($item_type, $item_id, $batch_number, $quantity_to_move, "{$move_to}", $requisition_id);
|
|
}
|
|
|
|
//function to create optical reconciliation
|
|
public function createOpticalReconciliation($item_type,$batche,$variance, $item_id, $physical_new_stock, $difference, $system_stock,$completion,$affected_account_id,$reconciliation_date,$general_comment,$max_stock_count_identifier):void
|
|
{
|
|
$batch = $batche[$item_id];
|
|
$physical_stock = new OpticalStockReconciliation;
|
|
$physical_stock->item_id = $item_id;
|
|
$physical_stock->system_stock = $system_stock;
|
|
$physical_stock->physical_stock = $physical_new_stock;
|
|
$physical_stock->difference = $difference;
|
|
$physical_stock->variance = $variance;
|
|
$physical_stock->batches = json_encode($batche[$item_id]);
|
|
$physical_stock->reason_for_difference = null;
|
|
$physical_stock->affected_account_id = $affected_account_id;
|
|
$physical_stock->completion_status = $completion;
|
|
$physical_stock->reconciliation_date = $reconciliation_date;
|
|
$physical_stock->stock_count_identifier = $max_stock_count_identifier+1;//increase ID by 1 for new
|
|
$physical_stock->general_comment = $general_comment;
|
|
$physical_stock->type =$item_type; //1 - pharmarcy, 0 - stores
|
|
$physical_stock->created_by = Auth::id();
|
|
$physical_stock->save();
|
|
if (isset($batch['reason_id'])){
|
|
foreach($batch['reason_id'] as $reason_id){
|
|
//update reconciliation reason
|
|
StockReconciliationReason::where('id', $reason_id)->update(['reconciliation_id' => $physical_stock->id]);
|
|
}
|
|
|
|
}
|
|
}
|
|
//save reconciliation reason
|
|
public function saveReconciliationReason($item_type,$item_id,$reason,$source):int
|
|
{
|
|
$reason_stock = new StockReconciliationReason;
|
|
$reason_stock->item_id = $item_id;
|
|
$reason_stock->item_type = $item_type;
|
|
$reason_stock->reason_id = $reason;
|
|
$reason_stock->source = $source;
|
|
$reason_stock->created_by = Auth::id();
|
|
$reason_stock->save();
|
|
return $reason_stock->id;
|
|
}
|
|
|
|
public function reconcileBatches($batches,$reason,$source, $item_type, $item_id, $batch_number, $batch_quantity, $batch_expiry_date, $store_or_pharmacy, $batch_unit_cost, $batch_records_db_id, $ward_id): array
|
|
{
|
|
$batch_record = ItemBatchWatcher::find($batch_records_db_id);
|
|
|
|
if ($batch_record) {
|
|
$item_batch_watcher = $batch_record;
|
|
} else {
|
|
$item_batch_watcher = new ItemBatchWatcher;
|
|
$item_batch_watcher->item_id = $item_id;
|
|
$item_batch_watcher->item_type = $item_type;
|
|
}
|
|
|
|
// Determine the original quantity based on store_or_pharmacy
|
|
$original_quantity = 0;
|
|
switch ($store_or_pharmacy) {
|
|
case 'store':
|
|
$original_quantity = $item_batch_watcher->store_stock ?? 0;
|
|
break;
|
|
case 'pharmacy':
|
|
$original_quantity = $item_batch_watcher->pharmacy_stock ?? 0;
|
|
break;
|
|
case 'lab':
|
|
$original_quantity = $item_batch_watcher->lab_stock ?? 0;
|
|
break;
|
|
case 'ward':
|
|
// Special handling for ward stock (aggregate or specific ward)
|
|
$exploded_ward_stocks = $item_batch_watcher->ward_stock ? explode(",", $item_batch_watcher->ward_stock) : [];
|
|
$exploded_ward_ids = $item_batch_watcher->ward_id ? explode(",", $item_batch_watcher->ward_id) : [];
|
|
$ward_id_key = array_search($ward_id, $exploded_ward_ids);
|
|
$original_quantity = $ward_id_key !== false ? ($exploded_ward_stocks[$ward_id_key] ?? 0) : 0;
|
|
break;
|
|
}
|
|
|
|
$original_values = [
|
|
'original_unit_cost' => $item_batch_watcher->cost_price ?? 0,
|
|
'original_quantity' => $original_quantity,
|
|
'original_batch_number' => $item_batch_watcher->batch_number ?? null,
|
|
];
|
|
|
|
$adjusted_values = [
|
|
'batch_id' => $batch_record->id??null,
|
|
'unit_cost' => $batch_unit_cost,
|
|
'quantity' => $batch_quantity,
|
|
'expiry_date' => $batch_expiry_date,
|
|
'batch_number' => $batch_number,
|
|
];
|
|
|
|
if (isset($batches[$item_id])) {
|
|
$batch_exists = false;
|
|
foreach ($batches[$item_id] as &$data) {
|
|
// Check if batch_id exists
|
|
if(isset($data['batch_id'])){
|
|
if ($data['batch_id'] == $batch_record->id) {
|
|
$batch_exists = true;
|
|
// Update the existing batch
|
|
$data['original_unit_cost'] = $original_values['original_unit_cost'];
|
|
$data['original_quantity'] = $original_values['original_quantity'];
|
|
$data['original_batch_number'] = $original_values['original_batch_number'];
|
|
|
|
$data['unit_cost'] = $batch_unit_cost;
|
|
$data['quantity'] = $batch_quantity;
|
|
$data['expiry_date'] = $batch_expiry_date;
|
|
$data['batch_number'] = $batch_number;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// If batch_id doesn't exist, add new batch
|
|
if (!$batch_exists) {
|
|
$batches[$item_id][] = array_merge($original_values, $adjusted_values);
|
|
}
|
|
} else {
|
|
$batches[$item_id][] = array_merge($original_values, $adjusted_values);
|
|
}
|
|
|
|
// Update ItemBatchWatcher
|
|
$item_batch_watcher->batch_number = $batch_number;
|
|
is_null($batch_unit_cost) ? "" : $item_batch_watcher->cost_price = $batch_unit_cost;
|
|
|
|
if ($store_or_pharmacy == "store") {
|
|
$item_batch_watcher->store_stock = $batch_quantity;
|
|
}
|
|
if ($store_or_pharmacy == "pharmacy") {
|
|
$item_batch_watcher->pharmacy_stock = $batch_quantity;
|
|
}
|
|
if ($store_or_pharmacy == "lab"){
|
|
$item_batch_watcher->lab_stock = $batch_quantity;
|
|
}
|
|
if ($store_or_pharmacy == "ward") {
|
|
|
|
$exploded_ward_stocks = $item_batch_watcher->ward_stock ? explode(",",$item_batch_watcher->ward_stock) : [];
|
|
$exploded_ward_ids = $item_batch_watcher->ward_id ? explode(",", $item_batch_watcher->ward_id) : [];
|
|
|
|
$ward_id_key = array_search($ward_id, $exploded_ward_ids);
|
|
|
|
if($ward_id_key !== false){
|
|
$exploded_ward_stocks[$ward_id_key] = $batch_quantity;
|
|
}
|
|
|
|
$item_batch_watcher->ward_stock = implode(",", $exploded_ward_stocks);
|
|
}
|
|
if($reason != ''){
|
|
$reason_id =$this->saveReconciliationReason($item_type,$item_id,$reason,$source);
|
|
$batches[$item_id]['reason_id'][] = $reason_id;
|
|
}
|
|
|
|
$item_batch_watcher->expiry_date = $batch_expiry_date;
|
|
$item_batch_watcher->save();
|
|
|
|
return $batches;
|
|
}
|
|
public function processReconcileItems($items_reconciled):EloquentCollection
|
|
{
|
|
foreach($items_reconciled as $item_reconciled){
|
|
$batches = json_decode($item_reconciled->batches,true) ;
|
|
//remove reason_id if exist
|
|
if(isset($batches['reason_id'])){
|
|
// Set reason_id property on the $item_reconciled object
|
|
$item_reconciled->reason_id = $batches['reason_id'];
|
|
// Remove reason_id from the batches array
|
|
unset($batches['reason_id']);
|
|
}
|
|
//modified batches array to JSON
|
|
//get reason
|
|
if(isset($item_reconciled->reason_id)){
|
|
foreach($item_reconciled->reason_id as $val){
|
|
$store_reason = StockReconciliationReason::find($val);
|
|
if (!is_null($store_reason)) {
|
|
$reason = ReconilicationReason::find($store_reason->reason_id);
|
|
if (!is_null($reason)){
|
|
$reasons[] = $reason->name;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
foreach($batches as $batch_key => $batch){
|
|
$batch['reason'] = isset($reasons[$batch_key]) ? $reasons[$batch_key] : null;
|
|
$batches[$batch_key] = $batch;
|
|
}
|
|
$item_reconciled->batches = $batches;
|
|
}
|
|
return $items_reconciled;
|
|
|
|
}
|
|
//function to get all reconciliation reasons
|
|
public function getAllReconciliationReasonsArray():array
|
|
{
|
|
return ReconilicationReason::orderBy('name','asc')->pluck('name','id')->prepend('Select Reason ', '')->toArray();
|
|
}
|
|
//function to return stock to any col stores or pharmacy
|
|
public function returnStockToAnySection($item_type,$drug_id,$ward_treatments_dispensation,$patient_id,$episode_id, $quantity_to_return,$stock_col,$selected_batch_id):void
|
|
{
|
|
if ($selected_batch_id !=null){
|
|
$batch_id = $selected_batch_id;
|
|
}else{
|
|
$batch_id = WardTreatmentBatchDispensation::where(['patient_id'=>$patient_id,'episode_id'=>$episode_id,'item_id'=>$drug_id])->value('item_batch_id');
|
|
}
|
|
//check for batch id
|
|
if($batch_id != null){
|
|
//get batch number that was consumed
|
|
$containsComma = array_filter([$batch_id], function($string) {
|
|
return strpos($string, ',') !== false;
|
|
});
|
|
if (!empty($containsComma)) {
|
|
$batch_id = explode(', ', $batch_id);
|
|
$batch_id = $batch_id[0];
|
|
}
|
|
|
|
//get item batch watcher record using batch number, item_type, item_id, where stock is not 0
|
|
$item_batch_watcher = ItemBatchWatcher::find($batch_id);
|
|
if ($item_batch_watcher) {
|
|
$item_batch_watcher->{$stock_col} = $item_batch_watcher->{$stock_col} + $quantity_to_return;
|
|
$item_batch_watcher->update();
|
|
}else{
|
|
// check if that drug has any batch number
|
|
$item_batch_watcher = ItemBatchWatcher::where(['item_type'=>$item_type, 'item_id'=>$drug_id, ])->where("{$stock_col}", '>', '0')->orderBy(DB::raw('ABS(DATEDIFF(expiry_date, NOW()))'))->first();
|
|
if ($item_batch_watcher) {
|
|
$item_batch_watcher->{$stock_col} = $item_batch_watcher->{$stock_col} + $quantity_to_return;
|
|
$item_batch_watcher->update();
|
|
}else{
|
|
$item_batch_watcher = new ItemBatchWatcher;
|
|
$item_batch_watcher->item_type = $item_type;
|
|
$item_batch_watcher->item_id = $drug_id;
|
|
$item_batch_watcher->batch_number = 'RTS-00'.$drug_id;
|
|
$item_batch_watcher->{$stock_col} = $quantity_to_return;
|
|
$item_batch_watcher->cost_price = $ward_treatments_dispensation->cost_price;
|
|
// add one month to expiry date
|
|
$item_batch_watcher->expiry_date = date('Y-m-d', strtotime('+1 month'));
|
|
$item_batch_watcher->save();
|
|
}
|
|
}
|
|
|
|
}else{
|
|
// check if that drug has any batch number
|
|
$item_batch_watcher = ItemBatchWatcher::where(['item_type'=>$item_type, 'item_id'=>$drug_id, ])->where("{$stock_col}", '>', '0')->orderBy(DB::raw('ABS(DATEDIFF(expiry_date, NOW()))'))->first();
|
|
if ($item_batch_watcher) {
|
|
$item_batch_watcher->{$stock_col} = $item_batch_watcher->{$stock_col} + $quantity_to_return;
|
|
$item_batch_watcher->update();
|
|
}else{
|
|
$item_batch_watcher = new ItemBatchWatcher;
|
|
$item_batch_watcher->item_type = $item_type;
|
|
$item_batch_watcher->item_id = $drug_id;
|
|
$item_batch_watcher->batch_number = 'RTS-00'.$drug_id;
|
|
$item_batch_watcher->{$stock_col} = $quantity_to_return;
|
|
$item_batch_watcher->cost_price = $ward_treatments_dispensation->cost_price;
|
|
// add one month to expiry date
|
|
$item_batch_watcher->expiry_date = date('Y-m-d', strtotime('+1 month'));
|
|
$item_batch_watcher->save();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} |