diff --git a/app/Http/Controllers/InvoiceValidationController.php b/app/Http/Controllers/InvoiceValidationController.php new file mode 100644 index 000000000..5f8499246 --- /dev/null +++ b/app/Http/Controllers/InvoiceValidationController.php @@ -0,0 +1,811 @@ +header('Authorization'); + $expectedToken = $expectedUser . ':' . $expectedPw; + + if ("Bearer " . $expectedToken != $header_auth) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Invalid authorization token!' + ], 403); + } + + try + { + $data = $request->all(); + + if (!isset($data['plant_code']) || trim($data['plant_code']) == '') + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Plant code can't be empty!" + ], 400); + } + else if (Str::length($data['plant_code']) < 4 || !is_numeric($data['plant_code']) || !preg_match('/^[1-9]\d{3,}$/', $data['plant_code'])) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Invalid plant code found!" + ], 400); + } + + $plant = Plant::where('code', $data['plant_code'])->first(); + if (!$plant) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Plant not found!' + ], 400); + } + + $plantId = $plant->id; + + if (!isset($data['item_codes']) || !is_array($data['item_codes']) || count($data['item_codes']) == 0) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'item_codes is required and must be a non-empty array!' + ], 400); + } + + //..Checking invoice number for empty or invalid length + + $invoiceNumber = $data['invoice_number'] ?? null; + + if (!$invoiceNumber || trim($invoiceNumber) == '') + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'invoice_number is required!' + ], 400); + } + else if (strlen(trim($invoiceNumber)) < 7) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'invoice number must contain at least 7 alphanumeric characters.' + ], 400); + } + + //..Checking item codes for invalid length + + $invalidItem = []; + foreach ($data['item_codes'] as $item) { + if (!isset($item['item_code']) || strlen(trim($item['item_code'])) < 6) { + $invalidItem[] = $item['item_code'] ?? '(missing item_code)'; + } + } + + if (!empty($invalidItem)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following item codes have invalid length (less than 6 characters)', + 'invalid_item_codes' => $invalidItem + ], 400); + } + + //..Checking item codes for invalid characters + + $invalidItemCodes = []; + foreach ($data['item_codes'] as $item) + { + $itemCode = $item['item_code'] ?? ''; + $trimmedCode = trim($itemCode); + if ($trimmedCode == '' || !ctype_alnum($trimmedCode)) + { + $invalidItemCodes[] = $item; + } + } + if (!empty($invalidItemCodes)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following item_code(s) contain invalid characters (only alphanumeric allowed).', + 'invalid_item_codes' => array_map(function($item) { + return $item['item_code'] ?? '(missing item_code)'; + }, $invalidItemCodes) + ], 400); + } + + //..Checking serial numbers for length less than 9 characters + + $invalidSerials = []; + foreach ($data['item_codes'] as $item) { + if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) { + foreach ($item['serial_numbers'] as $serial) { + if (strlen(trim($serial)) < 9) + { + $invalidSerials[] = $serial; + } + } + } + } + if (!empty($invalidSerials)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following serial numbers have invalid length (less than 9 characters)', + 'invalid_serial_numbers' => $invalidSerials + ], 400); + } + + //..Checking serial numbers for invalid characters + + $invalidSerialNumbers = []; + + foreach ($data['item_codes'] as $item) { + if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) { + foreach ($item['serial_numbers'] as $serial) { + $trimmedSerial = trim($serial); + if ($trimmedSerial == '' || !ctype_alnum($trimmedSerial)) { + $invalidSerialNumbers[] = $serial; + } + } + } + } + + if (!empty($invalidSerialNumbers)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following serial number(s) contain invalid characters (only alphanumeric allowed).', + 'invalid_serial_numbers' => $invalidSerialNumbers + ], 400); + } + + //Duplicate item code within json payload + $duplicateItemCode = []; + $seenCodes = []; + foreach ($data['item_codes'] as $item) + { + $code = $item['item_code'] ?? null; + if ($code == null) { + continue; + } + if (in_array($code, $seenCodes)) + { + if (!in_array($code, array_column($duplicateItemCode, 'item_code'))) { + $duplicateItemCode[] = $item; + } + } + else + { + $seenCodes[] = $code; + } + } + + if (!empty($duplicateItemCode)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Duplicate item_code found in request payload.", + 'duplicate_item_codes' => array_map(function($item) { + return $item['item_code'] ?? '(missing item_code)'; + }, $duplicateItemCode) + ], 400); + } + + //Duplicate serial numbers within all item_codes + $duplicateSno = []; + $seenSerials = []; + foreach ($data['item_codes'] as $item) + { + if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) { + foreach ($item['serial_numbers'] as $serial) { + if (in_array($serial, $seenSerials)) { + if (!in_array($serial, $duplicateSno)) { + $duplicateSno[] = $serial; + } + } else { + $seenSerials[] = $serial; + } + } + } + } + + if (!empty($duplicateSno)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Duplicate serial number found in request payload.", + 'duplicate_serial_numbers' => $duplicateSno + ], 400); + } + + //..Checking invoice number against plant in invoice validation table + + $totQuan = InvoiceValidation::where('invoice_number', $invoiceNumber)->count(); + + if ($totQuan > 0) + { + $scanSQuan = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('scanned_status', 'Scanned')->count(); + if ($totQuan == $scanSQuan) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Serial invoice number : '$invoiceNumber' completed the scanning process. Scan the next 'Serial Invoice' to proceed!", + ], 400); + } + else + { + $invoiceFirst = InvoiceValidation::with('plant')->where('invoice_number', $invoiceNumber)->first(); + $plantCode = $invoiceFirst ? (String)$invoiceFirst->plant->code : null; + if ($data['plant_code'] != $plantCode) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Serial invoice number : '$invoiceNumber' already exists for plant code : '$plantCode'. Pass the valid 'Plant Code' proceed!", + ], 400); + } + } + } + + //In item codes array serial numbers not exists + $snoNotExist = []; + foreach ($data['item_codes'] as $item) + { + if (!isset($item['item_code']) || !isset($item['serial_numbers']) || !is_array($item['serial_numbers'])) + { + //$snoNotExist[] = $item; + $snoNotExist[] = $item['item_code'] ?? '(missing item_code)'; + } + } + + if(!empty($snoNotExist)){ + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "item_codes array must have an item_code and an array of serial_numbers below item code doesn't have serial number array.", + 'item_codes' => $snoNotExist + ], 400); + } + + $notFoundItemCodes = []; + foreach ($data['item_codes'] as $item) + { + $itemRecord = Item::where('code', $item['item_code'])->first(); + if (!$itemRecord) { + $notFoundItemCodes[] = $item['item_code']; + } + else + { + $itemId = $itemRecord->id; + } + } + + if (!empty($notFoundItemCodes)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "The following item code(s) were not found in items table", + 'item_codes' =>$notFoundItemCodes + ], 400); + } + + //..Checking Item Code aginst Plant in items table + $plant = Plant::find($plantId); + $notFouItePlant = []; + foreach ($data['item_codes'] as $item) + { + $itemRec = Item::where('code', $item['item_code']) + ->where('plant_id', $plantId) + ->first(); + if (!$itemRec) { + $notFouItePlant[] = $item['item_code']; + } + } + if (!empty($notFouItePlant)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "The following item code(s) were not found in items table for plant '" . ($plant ? $plant->name : 'Unknown'). "'", + 'item_codes' => $notFouItePlant + ], 400); + } + + + $notFouItemCodesStiMas = []; + foreach ($data['item_codes'] as $item) { + $itemRecord = Item::where('code', $item['item_code'])->first(); + if ($itemRecord) { + $itemId = $itemRecord->id; + $stickerMasterRecord = StickerMaster::where('item_id', $itemId)->first(); + if (!$stickerMasterRecord) { + $notFouItemCodesStiMas[] = $item['item_code']; + } + } + else + { + $notFouItemCodesStiMas[] = $item['item_code']; + } + } + + if (!empty($notFouItemCodesStiMas)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following item code(s) were not found in sticker master table', + 'item_codes' => $notFouItemCodesStiMas + ], 400); + } + + + //..Checking Item Code in sticker master table aginst Plant + + $notFouIteStickerPlant = []; + foreach ($data['item_codes'] as $item) + { + $stickerMasterRec = StickerMaster::where('item_id', $itemId) + ->where('plant_id', $plantId) + ->first(); + if (!$stickerMasterRec) { + $notFouIteStickerPlant[] = $item['item_code']; + } + } + if (!empty($notFouIteStickerPlant)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "The following item code(s) were not found in sticker master table for plant'" . ($plant ? $plant->name : 'Unknown'). "'", + 'item_codes' => $notFouIteStickerPlant + ], 400); + } + + $invalidSerialMasType = []; + foreach ($data['item_codes'] as $item) { + $itemRecord = Item::where('code', $item['item_code'])->first(); + + $itemId = $itemRecord->id; + + $stickerMaster = StickerMaster::where('item_id', $itemId) + ->where('plant_id', $plantId) + ->whereNotNull('material_type') + ->where('material_type', '!=', 0) + ->first(); + + if ($stickerMaster) { + $invalidSerialMasType[] = $item['item_code']; + } + } + if (!empty($invalidSerialMasType)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following item code(s) not belongs to serial invoice type in sticker master table', + 'item_codes' => $invalidSerialMasType + ], 400); + } + + + if ($totQuan > 0) + { + $scanSQuan = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('scanned_status', 'Scanned')->where('plant_id', $plantId)->count(); + $allSerialNumbers = []; + foreach ($data['item_codes'] as $item) { + if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) { + foreach ($item['serial_numbers'] as $serial) { + $allSerialNumbers[] = $serial; + } + } + } + // Check database for existing serial numbers for this plant + $existingSerials = InvoiceValidation::where('plant_id', $plantId) + ->where('invoice_number', '!=', $invoiceNumber) + ->whereIn('serial_number', $allSerialNumbers) + ->pluck('serial_number') + ->toArray(); + + if (!empty($existingSerials)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'serial numbers already exist for this plant in database.', + 'duplicate_serial_numbers' => $existingSerials, + ], 400); + } + + InvoiceValidation::where('invoice_number', $invoiceNumber) + ->where(function($query) { + $query->whereNull('motor_scanned_status')->orWhere('motor_scanned_status', ''); + }) + ->where(function($query) { + $query->whereNull('pump_scanned_status')->orWhere('pump_scanned_status', ''); + }) + ->where(function($query) { + $query->whereNull('capacitor_scanned_status')->orWhere('capacitor_scanned_status', ''); + }) + ->where(function($query) { + $query->whereNull('scanned_status_set')->orWhere('scanned_status_set', ''); + }) + ->where(function($query) { + $query->whereNull('scanned_status')->orWhere('scanned_status', ''); + }) + ->forceDelete(); //->delete(); + + try + { + foreach ($data['item_codes'] as $item) + { + $stickerMasterId = $stickerMasterRecord->id; + + if (!isset($item['serial_numbers']) || !is_array($item['serial_numbers'])) { + continue; + } + + foreach ($item['serial_numbers'] as $serial) + { + $exists = InvoiceValidation::where('invoice_number', $invoiceNumber) + ->where('serial_number', $serial) + ->first(); + if ($exists) + { + $exists->updated_at = now(); + $exists->save(); + continue; + } + else + { + InvoiceValidation::create([ + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'item_code' => $item['item_code'], + 'serial_number' => $serial, + 'sticker_master_id' => $stickerMasterId, + 'updated_at' => now(), + ]); + } + + } + } + + return response()->json([ + 'status_code' => 'SUCCESS', + 'status_description' => 'Serial Invoice imported successfully!' + ], 200); + + } + catch (\Exception $e) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Failed to insert one or more serial invoice records: ' . $e->getMessage(), + ], 500); + } + } + else + { + $allSerialNumbers = []; + foreach ($data['item_codes'] as $item) { + if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) { + foreach ($item['serial_numbers'] as $serial) + { + $allSerialNumbers[] = $serial; + } + } + } + // Check database for existing serial numbers for this plant + $existingSerials = InvoiceValidation::where('plant_id', $plantId) + ->whereIn('serial_number', $allSerialNumbers) + ->pluck('serial_number') + ->toArray(); + + if (!empty($existingSerials)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'serial numbers already exist for this plant in database.', + 'duplicate_serial_numbers' => $existingSerials, + ], 400); + } + + //.. + try + { + foreach ($data['item_codes'] as $item) + { + $stickerMasterId = $stickerMasterRecord->id; + + foreach ($item['serial_numbers'] as $serial) + { + InvoiceValidation::create([ + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'item_code' => $item['item_code'], + 'serial_number' => $serial, + 'sticker_master_id' => $stickerMasterId, + ]); + } + } + return response()->json([ + 'status_code' => 'SUCCESS', + 'status_description' => 'Serial Invoice imported successfully!' + ], 200); + } + catch (\Exception $e) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Failed to insert one or more serial invoice records: ' . $e->getMessage(), + ], 500); + } + } + } + catch (\Exception $e) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => $e->getMessage(), + ], 500); + } + } + + public function materialInvoice(Request $request) + { + $expectedUser = env('API_AUTH_USER'); + $expectedPw = env('API_AUTH_PW'); + + $header_auth = $request->header('Authorization'); + $expectedToken = $expectedUser . ':' . $expectedPw; + + if ("Bearer " . $expectedToken != $header_auth) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Invalid authorization token!' + ], 403); + } + + try + { + $data = $request->all(); + if (!isset($data['plant_code']) || trim($data['plant_code']) == '') + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Plant code can't be empty!" + ], 400); + } + else if (Str::length($data['plant_code']) < 4 || !is_numeric($data['plant_code']) || !preg_match('/^[1-9]\d{3,}$/', $data['plant_code'])) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "Invalid plant code found!" + ], 400); + } + + $plant = Plant::where('code', $data['plant_code'])->first(); + if (!$plant) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'Plant not found!' + ], 400); + } + + $plantId = $plant->id; + + $invoiceNumber = $data['invoice_number'] ?? null; + + if (!$invoiceNumber || trim($invoiceNumber) == '') + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'invoice_number is required!' + ], 400); + } + else if (strlen(trim($invoiceNumber)) < 7) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'invoice number must contain at least 7 alphanumeric characters.' + ], 400); + } + + //..Checking item codes for invalid length + + $invalidItem = []; + foreach ($data['item_codes'] as $item) { + if (!isset($item['item_code']) || strlen(trim($item['item_code'])) < 6) { + $invalidItem[] = $item['item_code'] ?? '(missing item_code)'; + } + } + + if (!empty($invalidItem)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following item codes have invalid length (less than 6 characters)', + 'invalid_item_codes' => $invalidItem + ], 400); + } + + //..Checking item codes for invalid characters + + $invalidItemCodes = []; + foreach ($data['item_codes'] as $item) + { + $itemCode = $item['item_code'] ?? ''; + $trimmedCode = trim($itemCode); + if ($trimmedCode == '' || !ctype_alnum($trimmedCode)) + { + $invalidItemCodes[] = $item; + } + } + if (!empty($invalidItemCodes)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following item_code(s) contain invalid characters (only alphanumeric allowed).', + 'invalid_item_codes' => array_map(function($item) { + return $item['item_code'] ?? '(missing item_code)'; + }, $invalidItemCodes) + ], 400); + } + + //..Checking item codes in items table + + $notFoundItemCodes = []; + foreach ($data['item_codes'] as $item) + { + $itemRecord = Item::where('code', $item['item_code'])->first(); + if (!$itemRecord) { + $notFoundItemCodes[] = $item['item_code']; + } + } + + $itemId = $itemRecord->id; + if (!empty($notFoundItemCodes)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "The following item code(s) were not found in items table", + 'item_codes' =>$notFoundItemCodes + ], 400); + } + + //..Checking Item Code in sticker master table + + $notFouItemCodesStiMas = []; + foreach ($data['item_codes'] as $item) + { + $stickerMasterRecord = StickerMaster::where('item_id', $itemId)->first(); + if (!$stickerMasterRecord) { + $notFouItemCodesStiMas[] = $item['item_code']; + } + } + if (!empty($notFouItemCodesStiMas)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following item code(s) were not found in sticker master table', + 'item_codes' => $notFouItemCodesStiMas + ], 400); + } + + //..Checking Item Code aginst Plant in items table + $plant = Plant::find($plantId); + $notFouItePlant = []; + foreach ($data['item_codes'] as $item) + { + $itemRec = Item::where('code', $item['item_code']) + ->where('plant_id', $plantId) + ->first(); + if (!$itemRec) { + $notFouItePlant[] = $item['item_code']; + } + } + if (!empty($notFouItePlant)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "The following item code(s) were not found in items table for plant '" . ($plant ? $plant->name : 'Unknown'). "'", + 'item_codes' => $notFouItePlant + ], 400); + } + + //..Checking Item Code in sticker master table aginst Plant + + $notFouIteStickerPlant = []; + foreach ($data['item_codes'] as $item) + { + $stickerMasterRec = StickerMaster::where('item_id', $itemId) + ->where('plant_id', $plantId) + ->first(); + if (!$stickerMasterRec) { + $notFouIteStickerPlant[] = $item['item_code']; + } + } + if (!empty($notFouIteStickerPlant)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => "The following item code(s) were not found in sticker master table for plant'" . ($plant ? $plant->name : 'Unknown'). "'", + 'item_codes' => $notFouIteStickerPlant + ], 400); + } + + $invalidMaterialType = []; + foreach ($data['item_codes'] as $item) { + $itemRecord = Item::where('code', $item['item_code'])->first(); + + $itemId = $itemRecord->id; + + $stickerMaster = StickerMaster::where('item_id', $itemId) + ->where('plant_id', $plantId) + ->where(function($query) { + $query->whereNull('material_type') + ->orWhere('material_type', 0); + }) + ->first(); + + if ($stickerMaster) { + $invalidMaterialType[] = $item['item_code']; + } + } + if (!empty($invalidMaterialType)) { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => 'The following item code(s) belongs to seial invoice type in sticker master table', + 'item_codes' => $invalidMaterialType + ], 400); + } + + foreach ($data['item_codes'] as $item) + { + $quantity = isset($item['item_quantity']) ? (int)$item['item_quantity'] : null; + + InvoiceValidation::create([ + 'plant_id' => $plantId, + 'item_code' => $item['item_code'], + 'item_quantity' => $quantity, + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + + return response()->json([ + 'status_code' => 'SUCCESS', + 'status_description' => 'Invoice validation records inserted successfully.' + ], 200); + + } + catch (\Exception $e) + { + return response()->json([ + 'status_code' => 'ERROR', + 'status_description' => $e->getMessage(), + ], 500); + } + + } + + /** + * Display the specified resource. + */ + public function show(string $id) + { + // + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, string $id) + { + // + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(string $id) + { + // + } +} diff --git a/routes/api.php b/routes/api.php index 6f3268636..6bcaab17e 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,5 +1,6 @@