Compare commits

...

223 Commits

Author SHA1 Message Date
Edmond Lang 1c291134a1 admin move order 2026-01-25 23:39:44 +08:00
Edmond Lang 66576b6eea no message 2026-01-25 23:13:09 +08:00
Dillon Ngo 7be3614f96 New anthropic claude service to replace openai chatgpt 2026-01-25 15:31:00 +08:00
Dillon Ngo 9a1b33a413 Fix a problem reported by Eileen for an order with cbm calculation issue, removal of inline hardcode, use segment settings instead 2026-01-21 19:16:17 +08:00
Dillon Ngo 70ad358e5d Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2026-01-19 10:56:48 +08:00
Dillon Ngo c8249b9276 E-Invoice - Allow admin to download all reports 2026-01-19 10:56:14 +08:00
Dillon Ngo 0484eabb0e Quick fix for group payment issue got stuck reported by enqi 2026-01-06 10:20:04 +08:00
Dillon Ngo 7a5cf5f2ce Quick fix for group payment issue got stuck reported by enqi 2026-01-06 10:08:37 +08:00
Dillon Ngo 49a31a743c Allow all admin role type to view tracking no 2025-12-17 12:52:47 +08:00
Dillon Ngo f3d6521e2c CSS / UI Update 2025-12-09 11:01:49 +08:00
Dillon Ngo f7a9358202 Merge branch 'dillon/123-update-district-listing-ui-to-show-state-info' into vapor/production 2025-12-07 17:36:23 +08:00
Dillon Ngo db499bfecf Fix district listing to display state info for clarity when 2 state share the same district name 2025-12-07 16:53:28 +08:00
Dillon Ngo 0538653bca Fix district listing to display state info for clarity when 2 state share the same district name 2025-12-07 16:52:20 +08:00
Dillon Ngo 9147a4cfec Fix district listing to display state info for clarity when 2 state share the same district name 2025-12-07 16:13:08 +08:00
Dillon Ngo a20f4ed9be Fix district listing to display state info for clarity when 2 state share the same district name 2025-12-07 15:50:19 +08:00
Dillon Ngo d542a20f76 Fix district listing to display state info for clarity when 2 state share the same district name 2025-12-07 15:36:39 +08:00
Dillon Ngo 6d20c8d49e Fix district listing to display state info for clarity when 2 state share the same district name 2025-12-07 14:22:11 +08:00
Dillon Ngo f02220fda8 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-12-05 08:08:51 +08:00
Dillon Ngo 2bf511a1cb E-Invoice - Fix Process E-Invoices button missed some orders left unprocessed 2025-12-05 08:08:33 +08:00
Dillon Ngo 4242777e7d Fix double wallet top up for group payment transaction problem 2025-12-02 16:03:32 +08:00
Dillon Ngo 65bd979b31 Fix double wallet top up for group payment transaction problem 2025-12-02 12:23:12 +08:00
Dillon Ngo e0213108d2 Fix a broken link at wallet details page 2025-11-28 12:07:50 +08:00
Dillon Ngo 71f50b646b Fix a unsucccessful group payment reported by Eileen 2025-11-19 09:19:37 +08:00
Dillon Ngo 2a662b42e0 Fix a unsucccessful group payment reported by Eileen 2025-11-17 21:06:03 +08:00
Dillon Ngo 024e0d666a Fix a unsucccessful group payment reported by Eileen 2025-11-17 20:47:47 +08:00
Dillon Ngo 37119344f3 Fix a problem on invoice generated has incorrect freight service charge (reported by Brian) 2025-11-17 19:48:56 +08:00
Dillon Ngo 37cb4fca18 Fix an issue reported by Eileen on order tracking page drive info not support to appear 2025-11-13 21:37:24 +08:00
Dillon Ngo 37e8bf4d9a Attempt to fix container integration from YD API with duplication 2025-11-08 04:52:19 +08:00
Dillon Ngo 0df85daf2e E-Invoice - Update 'Process E-Invoice' date range filtering target 2025-11-06 23:08:24 +08:00
Dillon Ngo 650cfba74a E-Invoice - Update 'Process E-Invoice' date range filtering target 2025-11-06 22:40:16 +08:00
Dillon Ngo 7f94148ed9 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-24 13:37:07 +08:00
Dillon Ngo 539da4f551 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-24 13:35:47 +08:00
Dillon Ngo 7c8f5fe791 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-24 13:06:57 +08:00
Dillon Ngo 60c083a9cf E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-24 12:58:01 +08:00
Dillon Ngo 5b32fe9d6f E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-24 12:52:01 +08:00
Dillon Ngo d315880067 E-Invoice - Fix some problem reported y Mira on exporting report 2025-10-24 12:34:56 +08:00
Dillon Ngo 9cd2051cac E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 19:31:27 +08:00
Dillon Ngo 8c3e8fdeaf E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 19:18:48 +08:00
Dillon Ngo c31e7aaf37 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 19:06:41 +08:00
Dillon Ngo 5b6f419d9e E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 18:52:27 +08:00
Dillon Ngo c7f00a7ce2 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 18:17:56 +08:00
Dillon Ngo 35932e5351 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 18:04:13 +08:00
Dillon Ngo 012b88ee37 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 17:48:55 +08:00
Dillon Ngo 88869dcadb E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 17:30:15 +08:00
Dillon Ngo df1d80756a E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 17:10:57 +08:00
Dillon Ngo 066f5f52d5 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 16:54:44 +08:00
Dillon Ngo 4d76ffd545 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 16:15:17 +08:00
Dillon Ngo 58f62de2e8 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 16:03:12 +08:00
Dillon Ngo 773b30d224 E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 15:12:57 +08:00
Dillon Ngo 74811f177c E-Invoice - Update Sales Invoice Report to have paid and unpaid invoices in the report 2025-10-23 15:09:50 +08:00
Dillon Ngo 82de9ae6f9 E-Invoice - Update Sales Invoice Report 2025-10-21 15:57:15 +08:00
Dillon Ngo 6cb27096f7 E-Invoice - New Report Export (Sales Invoice Report, unpaid) 2025-10-18 15:08:48 +08:00
Dillon Ngo 10660b8350 Merge branch 'dillon/90-e-invoice-shipping-portal-e-1' into vapor/production 2025-10-14 12:41:26 +08:00
Dillon Ngo 5c42d383d0 Merge branch 'dillon/90-e-invoice-shipping-portal-f' into dillon/90-e-invoice-shipping-portal-e-1 (Lost Tracked Task) 2025-10-14 12:40:40 +08:00
Dillon Ngo d3966e8b28 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-10-05 13:47:12 +08:00
Dillon Ngo 6a4570442a E-Invoice - Amendment for storage invoice to generate E-Invoice 2025-10-05 12:12:45 +08:00
Edmond Lang 300f7b6642 fix bug: unexpected token "use" (View: /Users/edmondlang/Herd/shipping-portal/resources/views/pages/pdfs/shipping_invoices_sst_combined_v2.blade.php) 2025-10-03 16:41:36 +08:00
Dillon Ngo c28ee64878 Fix a problem reported by Brian where minimum charge not suppose to be applied 2025-10-01 18:26:52 +08:00
Dillon Ngo ce6b47763c E-Invoice - Amendment for storage invoice to generate E-Invoice (partial completion) 2025-09-29 14:21:03 +08:00
Dillon Ngo 881dd71ef0 E-Invoice - Amendment for storage invoice to generate E-Invoice (partial completion) 2025-09-26 09:27:26 +08:00
Dillon Ngo beec9aef24 E-Invoice - Amendment for storage invoice to generate E-Invoice (partial completion) 2025-09-26 09:04:39 +08:00
Dillon Ngo fcd6f2d6a8 E-Invoice - Amendment for storage invoice to generate E-Invoice (partial completion) 2025-09-25 17:46:33 +08:00
Dillon Ngo ae15575b0a E-Invoice - Update einvoice template qr code appearance (code sync from Exchange) 2025-09-24 17:24:01 +08:00
Dillon Ngo 4a66578380 E-Invoice - New Report Export (11D - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY] - Update 2025-09-24 13:10:49 +08:00
Dillon Ngo ffbf6b0f9c E-Invoice - New Report Export (11D - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY] - Update 2025-09-24 08:09:49 +08:00
Dillon Ngo 1e4d2c8031 E-Invoice - New Report Export (11D - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY] - Update 2025-09-23 17:20:29 +08:00
Dillon Ngo 2122d18be5 E-Invoice - Update to Sales Invoice Report template ref column 2025-09-23 17:06:43 +08:00
Dillon Ngo 0e9ef67121 Merge branch 'dillon/90-e-invoice-shipping-portal-f' into vapor/production 2025-09-23 13:31:40 +08:00
Dillon Ngo c2511e2467 E-Invoice - New Report Import (11R - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]) 2025-09-22 11:35:48 +08:00
Dillon Ngo e663165654 E-Invoice - New Report Import (11R - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]) 2025-09-22 11:21:39 +08:00
Dillon Ngo e80e52d04e E-Invoice - New Report Export (11R - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]) 2025-09-22 09:17:01 +08:00
Dillon Ngo eed5559cbf E-Invoice - New Report Export (11D - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY] 2025-09-19 14:44:31 +08:00
Dillon Ngo 7fdb579ab8 E-Invoice - New Report Export (11D - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY] 2025-09-19 12:11:17 +08:00
Dillon Ngo 6c5c5a9d34 Merge branch 'dillon/90-e-invoice-shipping-portal-f' into dillon/90-e-invoice-shipping-portal-e-1 2025-09-18 12:46:40 +08:00
Dillon Ngo 1d45a7aadf Remove redundant code 2025-09-16 14:04:03 +08:00
Dillon Ngo 81474625eb Remove redundant code 2025-09-16 13:52:59 +08:00
Dillon Ngo 769becfc16 E-Invoice - Code sync from Exchange 2025-09-16 12:59:33 +08:00
Dillon Ngo 6ee296ef06 New updated business logic for storage invoice calculation 2025-09-09 12:25:54 +08:00
Dillon Ngo e0e6e53e63 New updated business logic for storage invoice calculation 2025-09-07 21:20:15 +08:00
Dillon Ngo 9a90e8cf80 New updated business logic for storage invoice calculation 2025-09-06 15:13:12 +08:00
Dillon Ngo 4db8b24b22 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-09-02 05:19:39 +08:00
Dillon Ngo d5e008d4f3 E-Invoice - Reinstate some commented code 2025-09-02 05:09:39 +08:00
Dillon Ngo 7a6655c3d9 E-Invoice - Project 27, IZYIM - Sales Invoice - Batch process for E-Invoices 2025-09-02 04:56:44 +08:00
Dillon Ngo 7fbee7b047 E-Invoice - Project 27, IZYIM - Sales Invoice - Batch process for E-Invoices 2025-09-02 04:30:18 +08:00
Edmond Lang 2edd44a218 Update ExportsArrivedParcel -> so that the "/warehouse-list" Arrived Parcel is showing the same thing as the export 2025-09-01 22:10:49 +08:00
Edmond Lang a8d86eebd6 fix php error for HasParcelWithTransportBetweenDate 2025-09-01 22:00:13 +08:00
Edmond Lang 6f2b374cbd Add Filters for "/warehouse-list" -> Arrived Parcel 2025-09-01 20:46:45 +08:00
Dillon Ngo 3fb7befd62 E-Invoice - Project 27, IZYIM - Sales Invoice - Import 2025-08-31 17:39:07 +08:00
Dillon Ngo 8607caa84f E-Invoice - Project 27, IZYIM - Sales Invoice - Import 2025-08-31 17:04:57 +08:00
Dillon Ngo 47d564ec09 E-Invoice - Project 27, IZYIM - Sales Invoice - Export 2025-08-30 18:11:27 +08:00
Dillon Ngo 8031db446e Merge branch 'vapor/production' into dillon/90-e-invoice-shipping-portal-e 2025-08-28 10:16:03 +08:00
Dillon Ngo 62177bd3d0 Fix Identification verification listing for admin at dashboard not showing properly 2025-08-19 01:15:50 +08:00
Dillon Ngo 76512b107b Merge branch 'vapor/production' into dillon/90-e-invoice-shipping-portal-e 2025-08-19 01:07:33 +08:00
Dillon Ngo b8f284c2c0 Cleanup + Code Refactor 2025-08-16 10:39:45 +08:00
Dillon Ngo 5db1579c36 Cleanup + Code Refactor 2025-08-16 10:30:58 +08:00
Dillon Ngo 7615c3ef3e Merge branch 'vapor/production' into dillon/100-cleanup 2025-08-16 10:23:04 +08:00
Dillon Ngo d8f1262ec2 Cleanup + Code Refactor 2025-08-15 09:14:43 +08:00
Dillon Ngo 5b8893068c Fix a problem reported by Eileen of a group payment double charge problempayment through wallet 2025-08-14 04:12:54 +08:00
Dillon Ngo 1810809113 Fix a problem reported by Eileen of a group payment double charge problempayment through wallet 2025-08-14 03:39:52 +08:00
Dillon Ngo 9d4daeeb46 Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-11 11:44:14 +08:00
Dillon Ngo 84e23ec80f Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-08-11 11:40:37 +08:00
Dillon Ngo 5b2e3a1828 Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-11 11:39:45 +08:00
Dillon Ngo c52b577c19 Cleanup + Code Refactor 2025-08-11 04:59:58 +08:00
Dillon Ngo 8f6443d536 Merge branch 'dillon/90-e-invoice-shipping-portal-e-2' into vapor/production 2025-08-09 23:23:18 +08:00
Dillon Ngo 5414be594d Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-09 21:16:05 +08:00
Dillon Ngo 0625c37cdc Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-09 20:30:42 +08:00
Dillon Ngo bdc45282a4 Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-09 20:12:37 +08:00
Dillon Ngo a716a7a38b Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-09 19:55:05 +08:00
Dillon Ngo b3d904f3c8 Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-09 19:16:29 +08:00
Dillon Ngo d8f3f50bb0 Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-09 18:44:31 +08:00
Dillon Ngo 6d26f690c0 Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-09 18:10:53 +08:00
Dillon Ngo f061b5eb86 Debug an old 504 problem at payment-and-billing page > pending payment tab with no data 2025-08-09 17:35:05 +08:00
Dillon Ngo e83e8aa5c8 Merge branch 'dillon/90-e-invoice-shipping-portal-b-debug-1' into dillon/90-e-invoice-shipping-portal-e-2 2025-08-09 17:24:43 +08:00
Dillon Ngo b6e4bbd94c Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-08-08 22:21:03 +08:00
Dillon Ngo ca8e69b17a E-Invoice - State list to only show Malaysia states 2025-08-08 22:08:13 +08:00
Edmond Lang d99566a431 sin yee's request: add email for debtor's export 2025-08-06 21:43:45 +08:00
Dillon Ngo 6ce38e5751 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-08-05 19:48:05 +08:00
Dillon Ngo 8564667c62 Fix a problem reported by Eileen where storage invoice has negative charges 2025-08-05 19:47:42 +08:00
Edmond Lang 7da665ca5b Fix: negative storage fee issue 2025-08-05 17:27:04 +08:00
Edmond Lang 2cee63789b Fix: negative storage fee issue 2025-08-05 17:14:50 +08:00
Dillon Ngo 8fbd377965 E-Invoice - Emergency fix error reported by Eileen pending approval list at payment & billing page not showing anything 2025-08-04 17:25:04 +08:00
Dillon Ngo 11ac78881c Merge branch 'dillon/90-e-invoice-shipping-portal-f' into vapor/production 2025-07-31 23:57:30 +08:00
Dillon Ngo cc49336a4d Merge branch 'dillon/90-e-invoice-shipping-portal-b-2' into vapor/production 2025-07-30 22:11:37 +08:00
Dillon Ngo 1380d99109 E-Invoice - Project 27: Import Tax Entity, Customers Data Report 2025-07-30 21:44:55 +08:00
Edmond Lang 42e6e82df8 if billing address is null, when update e invoice details, add billing address 2025-07-24 21:49:24 +08:00
Dillon Ngo 7cac5b937f E-Invoice - IZYIM DOC DELIVERY - Part 2 (updated business logic) 2025-07-24 17:55:30 +08:00
Dillon Ngo 812f16a191 E-Invoice - IZYIM DOC DELIVERY - Part 2 (updated business logic) 2025-07-24 17:47:44 +08:00
Dillon Ngo 1073b6484c Merge branch 'dillon/90-e-invoice-shipping-portal-e' into dillon/90-e-invoice-shipping-portal-b-2 2025-07-24 16:46:15 +08:00
Dillon Ngo 549bf98725 E-Invoice - New request from Anitha billing address should follow einvoice address if exist at Pending Invoice tab at payment and billing page 2025-07-24 06:18:14 +08:00
Dillon Ngo e3afc2b008 Fix Paid Group Invoices 504 error 2025-07-09 01:19:02 +08:00
Dillon Ngo d0decc6c7b Merge branch 'vapor/production' into dillon/90-e-invoice-shipping-portal-e 2025-07-09 00:11:32 +08:00
Dillon Ngo 312b467564 Paid Group Invoices 504 error debug 2025-07-08 23:32:16 +08:00
Dillon Ngo 7adf03cf06 E-Invoice - IZYIM DOC DELIVERY - Part 2 - debug 2025-07-08 13:21:19 +08:00
Dillon Ngo 018c3eb755 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-07-08 02:42:43 +08:00
Dillon Ngo b8707fbb0d Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-07-08 02:42:25 +08:00
Dillon Ngo 134e0d86ea E-Invoice - Disable auto generate E-Invoice 2025-07-08 02:42:05 +08:00
Dillon Ngo 3d70a42758 E-Invoice - IZYIM DOC DELIVERY - Part 2 (updated business logic) 2025-07-08 02:39:20 +08:00
Dillon Ngo 9ef56454a0 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-07-07 23:30:03 +08:00
Dillon Ngo ea1c447fa1 Fix a UI problem reported by Joanne for clarity 2025-07-07 23:29:49 +08:00
Dillon Ngo 79679fe2e0 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-07-07 23:15:28 +08:00
Dillon Ngo 5c1a4536f6 Fix a problem reported by Yien where admin cannot approve an invoice 2025-07-07 23:15:13 +08:00
Dillon Ngo 345c8d24ca E-Invoice - IZYIM DOC DELIVERY - Part 2 2025-07-07 05:36:50 +08:00
Dillon Ngo d986787c4c Merge branch 'dillon/90-e-invoice-shipping-portal-e-1' into dillon/90-e-invoice-shipping-portal-b-2 2025-07-06 19:31:16 +08:00
Dillon Ngo 3281625e92 Looked into a 504 error order show page 2025-07-06 03:15:52 +08:00
Dillon Ngo 71e9a479d9 Looked into a 504 error order show page 2025-07-06 01:58:16 +08:00
Dillon Ngo 5fef38a04b Looked into a 504 error order show page 2025-07-05 16:01:42 +08:00
Dillon Ngo bf22b86a02 Looked into a 504 error order show page 2025-07-05 14:52:50 +08:00
Dillon Ngo 3b0738219f E-Invoice - Fix a problem with normal invoice shown to user opted in for einvoice 2025-07-05 01:58:24 +08:00
Dillon Ngo 18434903ac Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-07-04 00:13:34 +08:00
Dillon Ngo c2d51fc502 E-Invoice - Hide 'Change Billing Address' button when user already opt in for e-invoice 2025-07-04 00:11:24 +08:00
Dillon Ngo be0d10416b Merge branch 'dillon/90-e-invoice-shipping-portal-b' into vapor/production 2025-07-03 13:53:09 +08:00
Dillon Ngo 9cc80e6965 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into dillon/90-e-invoice-shipping-portal-b-2 2025-07-03 06:24:10 +08:00
Dillon Ngo 9991524a2e Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-07-03 06:17:03 +08:00
Dillon Ngo 7808d0d5ae Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-07-03 06:16:12 +08:00
Dillon Ngo 3d7d571370 E-Invoice -
Allow SSM Registration / Identification Card number to be upda
ted without a document upload mainly for old customer
2025-07-02 19:02:14 +08:00
Dillon Ngo 955b454630 E-Invoice -
Allow SSM Registration / Identification Card number to be upda
ted without a document upload mainly for old customer
2025-07-02 18:54:24 +08:00
Dillon Ngo f45ea797d6 E-Invoice -
Allow SSM Registration / Identification Card number to be upda
ted without a document upload mainly for old customer
2025-07-02 18:40:46 +08:00
Dillon Ngo efd734bbdb Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-07-02 00:48:32 +08:00
Dillon Ngo 0c849ee302 E-Invoice - New request to allow user to change of mi
nd when filling up einvoice info form to opt out when they already opt in for e-invoice
2025-07-02 00:13:02 +08:00
Edmond Lang 9c9d4fe594 update menu icon 2025-07-01 12:37:09 +08:00
Dillon Ngo 167216c26f Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-06-30 23:48:46 +08:00
Dillon Ngo d97796d885 E-Invoice - Disable maintenance page for normal user 2025-06-30 23:33:05 +08:00
Dillon Ngo 2bd66f6786 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-06-30 15:46:33 +08:00
Dillon Ngo c64f6f5da5 E-Invoice - Sin Yee requestion for ability for admin to edit SSM Registration and Identification Card 2025-06-30 15:46:09 +08:00
Dillon Ngo da7843c5df E-Invoice - Sin Yee requestion for ability for admin to edit SSM Registration and Identification Card 2025-06-30 00:45:41 +08:00
Dillon Ngo 2463e419c8 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-06-29 17:53:18 +08:00
Dillon Ngo 2cbee23234 E-Invoice - Debug Pending Payment at /payment-and-billing no data (undo) 2025-06-29 17:52:07 +08:00
Dillon Ngo dca9682c59 E-Invoice - Debug Pending Payment at /payment-and-billing no data (undo) 2025-06-29 17:38:52 +08:00
Dillon Ngo b417ba074e E-Invoice - Sin Yee request for einvoice postcode need to able to input starting with 0, e.g. 02600 2025-06-29 16:22:15 +08:00
Edmond Lang 5767ab1853 add new menu "E-Invoice Guideline" - open in new tab 2025-06-28 23:41:03 +08:00
Dillon Ngo a7aad5373b E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 19:51:52 +08:00
Dillon Ngo cad314d6a7 E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 19:25:57 +08:00
Dillon Ngo 137dfe0669 E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 17:14:33 +08:00
Dillon Ngo 52b839c741 E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 16:32:22 +08:00
Dillon Ngo d8ee9f1e67 Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/production 2025-06-28 16:13:14 +08:00
Dillon Ngo 620b9651a3 Merge branch 'dillon/90-e-invoice-shipping-portal-a' into dillon/90-e-invoice-shipping-portal-e 2025-06-28 16:11:54 +08:00
Dillon Ngo c37ed89a73 E-Invoice - Minor amendment requested by Harry on TIN length validation 2025-06-28 15:57:09 +08:00
Dillon Ngo f56548efa7 E-Invoice - Minor amendment requested by Harry on TIN length validation 2025-06-28 15:30:16 +08:00
Dillon Ngo 679bb9978a E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 13:49:32 +08:00
Dillon Ngo 2c6b8ac7ea Merge branch 'dillon/90-e-invoice-shipping-portal-a' into dillon/90-e-invoice-shipping-portal-b-debug-1 2025-06-28 13:46:44 +08:00
Dillon Ngo 9b7a5a6f1e Merge branch 'dillon/90-e-invoice-shipping-portal-a' into dillon/90-e-invoice-shipping-portal-b 2025-06-28 13:46:19 +08:00
Dillon Ngo fbf5fb290e Merge branch 'dillon/90-e-invoice-shipping-portal-a' into vapor/production 2025-06-28 13:45:49 +08:00
Dillon Ngo 63902e9266 E-Invoice - Allow admin to update E-Invoice info on behalf of customer 2025-06-28 13:45:24 +08:00
Dillon Ngo 1a318ead7e E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 13:35:42 +08:00
Dillon Ngo bd8b212f6f E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 12:49:18 +08:00
Dillon Ngo 59fbdfa789 E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 12:27:52 +08:00
Dillon Ngo 2bd96075cc E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 12:14:20 +08:00
Dillon Ngo c046a533d8 E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 11:35:02 +08:00
Dillon Ngo 8e6c70c67b E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 11:14:44 +08:00
Dillon Ngo 878e69fdb0 E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 11:00:34 +08:00
Dillon Ngo e047632de0 E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 10:45:55 +08:00
Dillon Ngo 8d75da288a E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 10:32:48 +08:00
Dillon Ngo ab5a94cbc0 E-Invoice - Debug Pending Payment at /payment-and-billing no data 2025-06-28 10:16:48 +08:00
Edmond Lang 17d8c82cff update /export/all-customers-info-for-lark-system, fix duplications on customer connections - use the first one 2025-06-27 16:53:28 +08:00
Edmond Lang 8f80c7ac8c Merge branch 'vapor/production' of https://gitlab.com/CIEFWorldwideSdnBhd/shipping-portal into vapor/production 2025-06-27 16:24:49 +08:00
Edmond Lang 9c09b1e01d update /export/all-customers-info-for-lark-system, fix duplications on customer connections - use the first one 2025-06-27 16:21:28 +08:00
Dillon Ngo 6911eba119 E-Invoice - Updated maintenance message 2025-06-27 12:52:05 +08:00
Dillon Ngo c564a8ed70 E-Invoice - Updated maintenance message 2025-06-27 12:46:18 +08:00
Dillon Ngo 273f81f9a8 E-Invoice - Updated maintenance message 2025-06-27 12:25:09 +08:00
Dillon Ngo ba1b287cbb E-Invoice - Minor UI update 2025-06-27 01:11:32 +08:00
Dillon Ngo 40d133aaab E-Invoice - Minor text display update 2025-06-27 00:43:41 +08:00
Dillon Ngo d52a52241c Merge branch 'dillon/90-e-invoice-shipping-portal-a' into dillon/90-e-invoice-shipping-portal-b 2025-06-27 00:40:19 +08:00
Dillon Ngo df9468d568 Merge branch 'dillon/90-e-invoice-shipping-portal-a' into vapor/production 2025-06-27 00:36:39 +08:00
Dillon Ngo 6d12f2d239 E-Invoice - Allow admin to view order without triggering rule checking 2025-06-27 00:34:14 +08:00
Dillon Ngo fe18d8bf5a Merge branch 'dillon/90-e-invoice-shipping-portal-a' into vapor/production 2025-06-27 00:26:57 +08:00
Dillon Ngo 3913d3c738 E-Invoice - Remove outdated code 2025-06-27 00:26:14 +08:00
Dillon Ngo be9df4afe3 Merge branch 'dillon/90-e-invoice-shipping-portal-a' into vapor/production 2025-06-27 00:07:06 +08:00
Dillon Ngo 82512bf4f6 E-Invoice - Sync some code fixes from Exchange to Shipping Portal 2025-06-26 23:13:17 +08:00
Dillon Ngo a9d4f3c839 E-Invo
ice - Maintenance notice for
normal user except admin
2025-06-26 20:04:11 +08:00
Dillon Ngo 218f0f8bca E-Invoice - IZYIM DOC DELIVERY 2025-06-26 18:29:15 +08:00
Edmond Lang 79db1dedc9 update /export/all-customers-info-for-lark-system, add is credit term customer 2025-06-26 17:45:13 +08:00
Edmond Lang 2aabd07ec4 update /export/all-customers-info-for-lark-system, add Debtor Code 2025-06-26 16:29:09 +08:00
Dillon Ngo 1d2eac806e E-Invoice - Initial commit main feature integration 2025-06-20 14:34:13 +08:00
Dillon Ngo 8d0fba2d21 E-Invoice - Initial commit main feature integration 2025-06-20 10:40:46 +08:00
Dillon Ngo b4c239f8a9 E-Invoice - Initial commit main feature integration 2025-06-20 10:00:26 +08:00
Dillon Ngo b3e8e5ea54 E-Invoice - Initial commit main feature integration 2025-06-20 09:41:17 +08:00
Edmond Lang ed4ec29d63 update /export/all-customers-info-for-lark-system 2025-06-13 00:44:03 +08:00
Edmond Lang ba5fd5f92d update /export/all-customers-info-for-lark-system 2025-06-13 00:36:23 +08:00
Edmond Lang e6028701db fix /export/all-customers-info-for-lark-system - handle json response 2025-06-12 23:53:47 +08:00
Edmond Lang fb2ca65168 add frontend for download /export/all-customers-info-for-lark-system 2025-06-12 23:31:09 +08:00
Edmond Lang 8ab9a0ba2d fix /export/all-customers-info-for-lark-system for php 7.4 issue 2025-06-12 23:03:38 +08:00
Edmond Lang 78ac0dbd8f test fix - {"message": "Endpoint request timed out"} 2025-06-12 22:48:58 +08:00
Edmond Lang e9c3af51c4 fix /export/all-customers-info-for-lark-system for php 7.4 issue 2025-06-12 22:35:10 +08:00
235 changed files with 16529 additions and 1852 deletions
+4
View File
@@ -66,3 +66,7 @@ COMMANDS_V2_ENABLED=false
STORAGE_FEE_LAUNCH_DATE="2023-12-11 00:00:00"
SST_START_DATE="2024-04-01 00:00:00"
E_INVOICE_START_DATE="2025-07-01 00:00:00"
MAINTENANCE_MESSAGE_TITLE="We'll be back online on 00:00 1/7/2025"
MAINTENANCE_MESSAGE="Sorry for the inconvenience but we're performing some maintenance at the moment."
@@ -0,0 +1,14 @@
<?php
namespace App\Classes\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class CriteriaNotFulfilledException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct(
$message ?? 'One or more required criteria were not fulfilled.',
HttpStatus::VALIDATION_FAILED
);
}
}
@@ -0,0 +1,38 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
class HasParcelWithTransportBetweenDate implements Filter
{
public static function apply(Builder $builder, $value)
{
if (is_string($value)) {
$value = json_decode($value, true) ?? [];
}
$startDate = Carbon::make(data_get($value, 'start_date'));
$endDate = Carbon::make(data_get($value, 'end_date'));
$start = $startDate ? $startDate->startOfDay() : null;
$end = $endDate ? $endDate->endOfDay() : null;
if (!$start && !$end) return $builder;
if ($start && $end && $start->gt($end)) [$start, $end] = [$end, $start];
return $builder->whereHas('transports', function (Builder $q) use ($start, $end) {
if ($start && $end && $start->isSameDay($end)) {
return $q->whereDate('drop_date', $start->toDateString());
}
if ($start && $end) {
return $q->whereBetween('drop_date', [$start, $end]);
}
return $start
? $q->where('drop_date', '>=', $start)
: $q->where('drop_date', '<=', $end);
});
}
}
@@ -28,6 +28,40 @@ class PackingListLimitOneByTypeOrderedByInvoiceDate implements Filter
SELECT id FROM transactions WHERE owner_id = packing_lists.id AND type = 16 LIMIT 1
))');
})->orderBy('transactions.updated_at', 'DESC');
}
//Original with problem
// return $builder->select('packing_lists.*')->join('transactions', function($join){
// $join->on('transactions.owner_id', '=', 'packing_lists.id');
// $join->where('transactions.owner_type', '=', PackingList::class);
// $join->where('transactions.status', '=', ApprovalStatus::APPROVED);
// $join->whereNull('transactions.deleted_at');
// $join->whereRaw('(transactions.type <> 16 OR transactions.id = (
// SELECT id FROM transactions WHERE owner_id = packing_lists.id AND type = 16 LIMIT 1
// ))');
// })->orderBy('transactions.updated_at', 'DESC');
//Attempt 1
// return $builder->with(['transactions' => function ($query) {
// $query->where('status', ApprovalStatus::APPROVED)
// ->whereNull('deleted_at')
// ->whereRaw('(
// transactions.type <> 16 OR transactions.id = (
// SELECT id FROM transactions AS t2
// WHERE t2.owner_id = transactions.owner_id
// AND t2.owner_type = ?
// AND t2.type = 16
// LIMIT 1
// )
// )', [PackingList::class])
// ->orderBy('updated_at', 'DESC');
// }]);
//Attempt 2
// return $builder->with(['transactions' => function ($query) {
// $query->where('status', ApprovalStatus::APPROVED)
// ->where('type', '<>', 16 )
// ->whereNull('deleted_at')
// ->orderBy('updated_at', 'DESC');
// }]);
}
}
@@ -23,6 +23,7 @@ class PackingListOrderedByInvoiceDate implements Filter
$join->on('transactions.owner_id', '=', 'packing_lists.id');
$join->where('transactions.owner_type', '=', PackingList::class);
$join->where('transactions.status', '=', ApprovalStatus::APPROVED);
$join->whereNull('transactions.deleted_at');
})->orderBy('transactions.updated_at', 'DESC');
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class TypeNotIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereNotIn('type', $value);
}
}
+67
View File
@@ -57,4 +57,71 @@ class Helper
static function deserializeFilters(?string $json): array {
return $json !== null ? collect(json_decode($json))->toArray() : [];
}
public static function getLHDNStateCodeByName($name)
{
$path = resource_path('data/lhdn/StateCodes.json');
if (!file_exists($path)) {
return null;
}
$json = file_get_contents($path);
$data = json_decode($json, true);
if (!is_array($data)) {
return null;
}
$name = strtolower(trim($name));
// Step 1: Try exact match
foreach ($data as $item) {
if (
isset($item['State']) &&
strtolower(trim($item['State'])) === $name
) {
return $item['Code'] ?? null;
}
}
// Step 2: Try partial match
foreach ($data as $item) {
if (
isset($item['State']) &&
str_contains(strtolower($item['State']), $name)
) {
return $item['Code'] ?? null;
}
}
return null;
}
public static function getLHDNMsicDescriptionByCode($code)
{
$path = resource_path('data/lhdn/MSICSubCategoryCodes.json');
if (!file_exists($path)) {
return null;
}
$json = file_get_contents($path);
$data = json_decode($json, true);
if (!is_array($data)) {
return null;
}
foreach ($data as $item) {
if (
isset($item['Code']) &&
$item['Code'] === $code
) {
return $item['Description'] ?? null;
}
}
return null;
}
}
@@ -0,0 +1,12 @@
<?php
namespace App\Classes\General\Interfaces;
use Illuminate\Database\Eloquent\Relations\MorphMany;
interface KeyValueInterface
{
public function attributesKVP(): morphMany;
}
@@ -0,0 +1,44 @@
<?php
namespace App\Classes\Jobs\Commands\V2;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Classes\Modules\Orders\Services\ListsOrders;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use App\Classes\ValueObjects\Constants\OrderType;
use Illuminate\Support\Facades\Log;
class CheckStorageInvoicesSingleOrderV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $order;
public function __construct($order)
{
$this->order = $order;
}
public function handle()
{
Log::info(Carbon::now() . ': Start job - Check single order for storage invoice.');
$start = new Carbon();
try{
Log::info("Processing Order - ID: {$this->order->id}, Reference: {$this->order->reference}");
(App()->make(CheckStorageInvoiceTransactionProcessor::class))->executeOrder($this->order);
}
catch(\Exception $ex){
Log::info('Exception '.$ex->getMessage());
}
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - Check single order for storage invoice. ElapsedTime: ' . $elapsedTime . '.');
}
}
@@ -8,16 +8,12 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Jobs\DataTransferObjects\FixInvoiceV2CommandObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Transactions\Processors\CreateShippingInvoiceTransactionDocProcessor;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\CompanyConnection;
use App\Models\Order;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use Illuminate\Support\Facades\Log;
class FixInvoiceV2CommandJob implements ShouldQueue
@@ -52,29 +48,10 @@ class FixInvoiceV2CommandJob implements ShouldQueue
dump($invoice->id);
$invoice->documents()->delete();
// $invoice->documents()->delete();
$invoice->documents()->where('document_type', DocumentType::SHIPPING_EINVOICE)->delete();
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
/** @var Document $document */
$document = (App()->make(CreatesDocument::class))->execute($invoice, $document_object);
(App()->make(CreatesFiles::class))->execute($document, $document_object);
(App()->make(CreateShippingInvoiceTransactionDocProcessor::class))->execute($invoice);
}
}
@@ -0,0 +1,49 @@
<?php
namespace App\Classes\Jobs\Commands\V2;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Classes\Modules\Transactions\Processors\CreatePaymentTransactionProcessor;
use App\Classes\Modules\Transactions\Processors\ReleaseGoodsToCustomerProcessor;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Models\Group;
use App\Models\Transaction;
use Illuminate\Support\Facades\Log;
class OneTimeFixWalletGroupTransactionV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
Log::info(Carbon::now() . ': Start job - This is a one time fix of unsuccessful group payment through wallet.');
$start = new Carbon();
$invoice_ids = [31493]; //31493
$invoices = Transaction::whereIn('id', $invoice_ids)->get();
foreach ($invoices as $invoice) {
if($invoice->status == ApprovalStatus::APPROVED){
$paymentTransaction = (App()->make(CreatePaymentTransactionProcessor::class))->execute($invoice, PaymentMethodType::WALLET, '', false);
if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
$pL = $invoice->owner;
(App()->make(ReleaseGoodsToCustomerProcessor::class))->execute($pL, $invoice);
}
}
}
$group = Group::where('id', 1569)->first(); //1569
$group->status = ApprovalStatus::APPROVED;
$group->save();
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - This is a one time fix of unsuccessful group payment through wallet. ElapsedTime: ' . $elapsedTime . '.');
}
}
@@ -20,13 +20,12 @@ class OneTimeTransactionFixBillplzFailedCbV2CommandJob implements ShouldQueue
public function handle()
{
Log::info(Carbon::now() . ': Start job - One time fix failled callback from billplz cron ended.');
Log::info(Carbon::now() . ': Start job - One time fix failled callback from billplz.');
$start = new Carbon();
//Transaction fix with this one time fix command: 15205, 16803, 17310, 22008, 6770
//This transaction, 16803 has approve payment but not its owner, shipping invoice
$transactions = Transaction::whereIn('id', [22008, 6770])->get();
Log::info(Carbon::now() . ' : One time fix failled callback from billplz started.');
foreach ($transactions as $transaction){
if($transaction){
@@ -40,6 +39,6 @@ class OneTimeTransactionFixBillplzFailedCbV2CommandJob implements ShouldQueue
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - One time fix failled callback from billplz cron ended. ElapsedTime: ' . $elapsedTime . '.');
Log::info(Carbon::now() . ': End job - One time fix failled callback from billplz. ElapsedTime: ' . $elapsedTime . '.');
}
}
@@ -0,0 +1,90 @@
<?php
namespace App\Classes\Jobs\Commands\V2;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair;
use App\Classes\Modules\Accounts\Services\UpdatesKeyValuePair;
use App\Classes\ValueObjects\Constants\KVPKey;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\KeyValuePair;
use Illuminate\Support\Facades\Log;
class ProcessPaymentReportV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** @var array */
private $details;
/**
* ProcessPaymentReportV2CommandJob constructor.
* @param array $details
*/
public function __construct(array $details)
{
$this->details = $details;
}
public function handle()
{
Log::info(Carbon::now() . ': Start job - Processing single record from 11R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT] Import.');
$start = new Carbon();
$docNo = $this->details['docno'] ?? null;
$docDate = $this->details['docdate'] ?? null;
$debtorCode = $this->details['debtorcode'] ?? null;
$description = $this->details['description'] ?? null;
$paymentMethod = $this->details['paymentmethod'] ?? null;
$paymentAmt = $this->details['paymentamt'] ?? null;
$knockOffDocNo = $this->details['knockoffdocno'] ?? null;
Log::info("Processing Payment Report:", [
'DocNo' => $docNo,
'DocDate' => $docDate,
'DebtorCode' => $debtorCode,
'Description' => $description,
'PaymentMethod' => $paymentMethod,
'PaymentAmt' => $paymentAmt,
'KnockOffDocNo' => $knockOffDocNo,
]);
if($knockOffDocNo){
$kvp = KeyValuePair::where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->where('value', $knockOffDocNo)->first();
if($kvp){
$transaction = $kvp->owner;
if($transaction){
if($docNo != "" && $docNo != "<<New>>"){
$this->updateOrCreateKeyValuePair($transaction, KVPKey::AUTOCOUNT_DOCNO_OFFICIAL_RECEIPT, $docNo);
}
// if($eInvoiceValidationLink){
// $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink);
// }
}
}
}
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - Processing single record from 11R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT] Import. ElapsedTime: ' . $elapsedTime . '.');
}
private function updateOrCreateKeyValuePair($booking, $key, $value)
{
$keyValuePairObject = new KeyValuePairObject($key, $value);
$metadata = $booking->attributesKVP()->where('key', $key)->first();
if ($metadata) {
(App()->make(UpdatesKeyValuePair::class))->execute($metadata, $keyValuePairObject);
} else {
(App()->make(CreatesKeyValuePair::class))->execute($booking, $keyValuePairObject);
}
}
}
@@ -0,0 +1,131 @@
<?php
namespace App\Classes\Jobs\Commands\V2;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair;
use App\Classes\Modules\Accounts\Services\UpdatesKeyValuePair;
use App\Classes\ValueObjects\Constants\KVPKey;
use App\Classes\ValueObjects\Constants\TransactionType;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Order;
use App\Models\Transaction;
use Illuminate\Support\Facades\Log;
class ProcessSalesInvoiceReportV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** @var array */
private $details;
/**
* ProcessSalesInvoiceReportV2CommandJob constructor.
* @param array $details
*/
public function __construct(array $details)
{
$this->details = $details;
}
public function handle()
{
Log::info(Carbon::now() . ': Start job - Processing single record for E-Invoice from Sales Invoice Report Import.');
$start = new Carbon();
$docNo = $this->details['docno'] ?? null;
$docDate = $this->details['docdate'] ?? null;
$debtorCode = $this->details['debtorcode'] ?? null;
$ref = $this->details['ref'] ?? null;
$shipInfo = $this->details['shipinfo'] ?? null;
$accNo = $this->details['accno'] ?? null;
$detailDescription = $this->details['detaildescription'] ?? null;
$furtherDescription = $this->details['furtherdescription'] ?? null;
$classification = $this->details['classification'] ?? null;
$projNo = $this->details['projno'] ?? null;
$deptNo = $this->details['deptno'] ?? null;
$qty = $this->details['qty'] ?? null;
$unitPrice = $this->details['unitprice'] ?? null;
$taxCode = $this->details['taxcode'] ?? null;
$taxableAmt = $this->details['taxableamt'] ?? null;
$taxRate = $this->details['taxrate'] ?? null;
$submitEinvoice = $this->details['submiteinvoice'] ?? null;
$consolidatedEinvoice = $this->details['consolidatedeinvoice'] ?? null;
$eInvoiceValidationLink = $this->details['einvoicevalidationlink'] ?? null;
// Log for debugging
Log::info("Processing Sales Invoice Report:", [
'DocNo' => $docNo,
'DocDate' => $docDate,
'DebtorCode' => $debtorCode,
'Ref' => $ref,
'ShipInfo' => $shipInfo,
'AccNo' => $accNo,
'DetailDescription' => $detailDescription,
'FurtherDescription' => $furtherDescription,
'Classification' => $classification,
'ProjNo' => $projNo,
'DeptNo' => $deptNo,
'Qty' => $qty,
'UnitPrice' => $unitPrice,
'TaxCode' => $taxCode,
'TaxableAmt' => $taxableAmt,
'TaxRate' => $taxRate,
'SubmitEinvoice' => $submitEinvoice,
'ConsolidatedEinvoice' => $consolidatedEinvoice,
'EInvoiceValidationLink' => $eInvoiceValidationLink,
]);
// $order = Order::where('reference', $ref)->first();
// $transactions = $order->transactions()->whereIn('transactions.type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])->get();
// $matchedTransaction = null;
// foreach ($transactions as $transaction) {
// $transactionDetails = $transaction->transactionDetails;
// foreach ($transactionDetails as $detail) {
// $detailName = str_replace('<br>', ' ', $detail->name);
// if (
// $detailName === $furtherDescription &&
// $detail->quantity == $qty &&
// $detail->price == $unitPrice
// ) {
// $matchedTransaction = $transaction;
// break 2;
// }
// }
// }
$matchedTransaction = Transaction::where('bill_no', $ref)->first();
if($matchedTransaction){
if($docNo != "" && $docNo != "<<New>>"){
$this->updateOrCreateKeyValuePair($matchedTransaction, KVPKey::AUTOCOUNT_DOCNO_INVOICE, $docNo);
}
if($eInvoiceValidationLink){
$this->updateOrCreateKeyValuePair($matchedTransaction, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink);
}
}
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - Processing single record for E-Invoice from Sales Invoice Report Import. ElapsedTime: ' . $elapsedTime . '.');
}
private function updateOrCreateKeyValuePair($booking, $key, $value)
{
$keyValuePairObject = new KeyValuePairObject($key, $value);
$metadata = $booking->attributesKVP()->where('key', $key)->first();
if ($metadata) {
(App()->make(UpdatesKeyValuePair::class))->execute($metadata, $keyValuePairObject);
} else {
(App()->make(CreatesKeyValuePair::class))->execute($booking, $keyValuePairObject);
}
}
}
@@ -0,0 +1,72 @@
<?php
namespace App\Classes\Jobs\Commands\V2;
use App\Classes\Modules\Transactions\Processors\CreateShippingEInvoiceDocProcessor;
use App\Classes\Modules\Transactions\Processors\CreateStorageEInvoiceDocProcessor;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\KVPKey;
use App\Classes\ValueObjects\Constants\TransactionType;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Transaction;
use Illuminate\Support\Facades\Log;
class ProcessTransactionForEInvoiceV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** @var Transaction */
private $transaction;
/**
* ProcessTransactionForEInvoiceV2CommandJob constructor.
* @param Transaction $transaction
*/
public function __construct(Transaction $transaction)
{
$this->transaction = $transaction;
}
public function handle()
{
Log::info(Carbon::now() . ': Start job - Processing single transaction for E-Invoice.');
$start = new Carbon();
$isGenerated = false;
$companyModule = $this->transaction->owner->owner->companyModule;
if($companyModule->company->e_invoice === 1){
$document = $this->transaction->documents()->where('document_type', DocumentType::SHIPPING_EINVOICE)->first();
$kvp = $this->transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if(!$document && $kvp && $this->transaction->type == TransactionType::SHIPPING_INVOICE){
(App()->make(CreateShippingEInvoiceDocProcessor::class))->execute($this->transaction);
$isGenerated = true;
}
else {
$document2 = $this->transaction->documents()->where('document_type', DocumentType::STORAGE_EINVOICE)->first();
$kvp2 = $this->transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if(!$document2 && $kvp2 && $this->transaction->type == TransactionType::STORAGE_INVOICE){
(App()->make(CreateStorageEInvoiceDocProcessor::class))->execute($this->transaction);
$isGenerated = true;
}
}
}
if(!$isGenerated){
Log::info("NO E-Invoice generated for transaction with id: " . $this->transaction->id . ', order: ' . $this->transaction->owner->owner->reference );
}
else{
Log::info("E-Invoice generated for transaction with id: " . $this->transaction->id . ', order: ' . $this->transaction->owner->owner->reference );
}
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - Processing single transaction for E-Invoice. ElapsedTime: ' . $elapsedTime . '.');
}
}
@@ -0,0 +1,47 @@
<?php
namespace App\Classes\Jobs\Commands\V2;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Classes\Modules\Orders\Services\ListsOrders;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use App\Classes\Modules\Transactions\Processors\ReleaseGoodsToCustomerProcessor;
use App\Classes\ValueObjects\Constants\OrderType;
use Illuminate\Support\Facades\Log;
class ReleaseGoodsToCustomerV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $invoice;
public function __construct($invoice)
{
$this->invoice = $invoice;
}
public function handle()
{
Log::info(Carbon::now() . ': Start job - Release goods to customer.');
$start = new Carbon();
try{
$obj = json_encode($this->invoice);
Log::info("Processing Order - ID: {$this->invoice->id}, invoice: {$obj}");
$pL = $this->invoice->owner;
(App()->make(ReleaseGoodsToCustomerProcessor::class))->execute($pL, $this->invoice);
}
catch(\Exception $ex){
Log::info('Exception '.$ex->getMessage());
}
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - Release goods to customer. ElapsedTime: ' . $elapsedTime . '.');
}
}
@@ -0,0 +1,44 @@
<?php
namespace App\Classes\Modules\Accounts\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class KeyValuePairObject implements DataTransferObject
{
/** @var string */
private $key;
/** @var string */
private $value;
/**
* KeyValuePairObject constructor.
* @param string $key
* @param string $value
*/
public function __construct(string $key, string $value)
{
$this->key = $key;
$this->value = $value;
}
/**
* @return string
*/
public function getKey(): string
{
return $this->key;
}
/**
* @return string
*/
public function getValue(): string
{
return $this->value;
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord;
use App\Classes\General\Interfaces\KeyValueInterface;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Models\KeyValuePair;
class CreatesKeyValuePair extends AbstractUpdateRelationshipRecord
{
/**
* @param KeyValueInterface $kv
* @param KeyValuePairObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(KeyValueInterface $kv, KeyValuePairObject $object) {
$model = new KeyValuePair();
$model->key = $object->getKey();
$model->value = $object->getValue();
return $this->handler($kv->attributesKVP(), $model);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
use App\Classes\General\Eloquent\AbstractDeleteRecord;
use App\Models\KeyValuePair;
class DeletesKeyValuePair extends AbstractDeleteRecord
{
/**
* @param KeyValuePair $model
* @return mixed
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(KeyValuePair $model) {
return $this->handler($model);
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Models\KeyValuePair;
class UpdatesKeyValuePair extends AbstractUpdateRecord
{
/**
* @param KeyValuePair $model
* @param KeyValuePairObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(KeyValuePair $model, KeyValuePairObject $object) {
$model->key = $object->getKey();
$model->value = $object->getValue();
return $this->handler($model);
}
}
@@ -2,7 +2,7 @@
namespace App\Classes\Modules\Addresses\ControllersLogic;
use App\Classes\Exceptions\AccessForbiddenException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Addresses\Services\CreatesAddress;
use App\Classes\Modules\Addresses\Standards\Rules\CanCreateAddress;
@@ -11,6 +11,7 @@ use App\Classes\Modules\Addresses\Services\FetchesAddress;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Http\Resources\AddressResource;
use App\Models\Address;
use App\Models\CompanyModule;
@@ -67,7 +68,15 @@ class CreateBillingAddressLogic extends AbstractControllerLogic
public function logic(Request $request) : JsonResponse
{
$companyModule = $this->fetchesCompanyModule->execute(['id' => $request->input('company_module_id')]);
//cief todo: 90 - move this into canCreateAddress
$roleToCheck = Auth()->user()->type;
if (!in_array($roleToCheck, RoleTypes::ADMIN_ROLES)) {
if($companyModule->company->e_invoice === 1){
throw new AccessForbiddenException('Update of billing address not allowed.');
}
}
$address = $this->fetchesAddress->execute(['id' => $request->input('billing_address_id')]);
if ($address->type !== AddressType::BILLING || $address->id !== $companyModule->addresses->where('type', AddressType::BILLING)->first()->id) {
@@ -83,4 +92,4 @@ class CreateBillingAddressLogic extends AbstractControllerLogic
return $this->resourceResponse(new AddressResource($address));
}
}
}
@@ -6,6 +6,7 @@ namespace App\Classes\Modules\Addresses\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Addresses\Services\ListsAddresses;
use App\Classes\Modules\Addresses\Standards\Rules\CanListAddresses;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Http\Resources\AddressResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
@@ -51,13 +52,12 @@ class ListAddressesLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$this->canListAddresses->passes();
$query = $this->listsAddresses->execute($this->listsAddresses->deserializeFilters($request->input('filters')));
//$query = $this->listsAddresses->execute($this->listsAddresses->deserializeFilters($request->input('filters')));
$query = $this->listsAddresses->execute(array_merge($this->listsAddresses->deserializeFilters($request->input('filters')), ['type_not_in' => [AddressType::E_INVOICE]]));
return $this->collectionResponse(AddressResource::collection($query));
}
}
}
@@ -23,7 +23,7 @@ class AddressObject implements DataTransferObject
/** @var int */
private $districtId;
/** @var int */
/** @var string */
private $postCode;
/** @var int */
@@ -42,12 +42,12 @@ class AddressObject implements DataTransferObject
* @param int $countryId
* @param int $stateId
* @param int $districtId
* @param int $postCode
* @param string $postCode
* @param int $type
* @param int $status
* @param null|string $reference
*/
public function __construct(string $streetOne, ?string $streetTwo, int $countryId, int $stateId, int $districtId, int $postCode, int $type, int $status, ?string $reference = null)
public function __construct(string $streetOne, ?string $streetTwo, int $countryId, int $stateId, int $districtId, string $postCode, int $type, int $status, ?string $reference = null)
{
$this->streetOne = $streetOne;
$this->streetTwo = $streetTwo;
@@ -101,9 +101,9 @@ class AddressObject implements DataTransferObject
}
/**
* @return int
* @return string
*/
public function getPostCode(): int
public function getPostCode(): string
{
return $this->postCode;
}
@@ -133,4 +133,4 @@ class AddressObject implements DataTransferObject
}
}
}
@@ -0,0 +1,40 @@
<?php
namespace App\Classes\Modules\Addresses\Services;
use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord;
use App\Classes\General\Interfaces\Addressable;
use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
use App\Models\Address;
use App\Models\CompanyModule;
class UpsertsAddress extends AbstractUpdateRelationshipRecord
{
/**
* Create or update the company's address.
*
* @param Addressable $addressable
* @param AddressObject $object
* @param int $id
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Addressable $addressable, AddressObject $object, int $id)
{
//Create new or update?
$model = $addressable->addresses()->where('id', $id)->first() ?? new Address();
$model->reference = $object->getReference();
$model->street_one = $object->getStreetOne();
$model->street_two = $object->getStreetTwo();
$model->country_id = $object->getCountryId();
$model->state_id = $object->getStateId();
$model->district_id = $object->getDistrictId();
$model->postcode = $object->getPostCode();
$model->status = $object->getStatus();
$model->type = $object->getType();
return $this->handler($addressable->addresses(), $model);
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\Classes\Modules\Anthropic\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class CreatesClaudeResponse
{
/**
* @param string $userPrompt
* @param string $model
* @return null|object
* @throws MalformedRequestException
*/
public function execute(string $userPrompt, string $model = "") {
try {
$content = [];
$content[] = [
'type' => 'text',
'text' => $userPrompt,
];
$response = Http::withHeaders([
'x-api-key' => config('anthropic.api_key'),
'anthropic-version' => config('anthropic.api_version', '2023-06-01'),
'Content-Type' => 'application/json',
])->post(config('anthropic.base_url') . '/v1/messages', [
'model' => config('anthropic.default_model', 'claude-sonnet-4-5-20250929'),
'max_tokens' => 8192,
'messages' => [
[
'role' => 'user',
'content' => $content,
],
],
]);
if ($response->successful()) {
return $response->json();
} else {
Log::info('CreatesClaudeResponse error: ' . $response->body());
return null;
}
}
catch (\Illuminate\Http\Client\ConnectionException $exception) {
Log::info('ConnectionException' . json_encode($exception));
throw new ConnectionErrorException(
'Failed to connect to Claude API',
$exception->getMessage(),
$userPrompt,
$exception->getTraceAsString()
);
}
catch (\Exception $exception) {
Log::info('Exception' . json_encode($exception));
throw new MalformedRequestException(
'Unable to get correct response from Claude API: ' . $exception->getMessage()
);
}
}
}
@@ -0,0 +1,67 @@
<?php
namespace App\Classes\Modules\Anthropic\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
class CreatesClaudeResponseWithFiles
{
public function execute(string $userPrompt, array $fileIds)
{
try {
$content = [];
// User prompt
$content[] = [
'type' => 'text',
'text' => $userPrompt,
];
// Attach files
foreach ($fileIds as $fileId) {
$content[] = [
'type' => 'document',
'source' => [
'type' => 'file',
'file_id' => $fileId,
],
];
}
$response = Http::withHeaders([
'x-api-key' => config('anthropic.api_key'),
'anthropic-version' => config('anthropic.api_version', '2023-06-01'),
'anthropic-beta' => 'files-api-2025-04-14',
'Content-Type' => 'application/json',
])->post(config('anthropic.base_url') . '/v1/messages', [
'model' => config('anthropic.default_model', 'claude-sonnet-4-5-20250929'),
'max_tokens' => 16384,
'messages' => [
[
'role' => 'user',
'content' => $content,
],
],
]);
return $response->json();
}
catch (\Illuminate\Http\Client\ConnectionException $exception) {
$error = 'Failed to connect to Claude API';
throw new ConnectionErrorException(
$error,
$exception->getMessage(),
$userPrompt,
$exception->getTraceAsString()
);
}
catch (\Exception $exception) {
throw new MalformedRequestException(
'Unable to get correct response from Claude API: ' . $exception->getMessage()
);
}
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\Anthropic\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
class UploadsClaudeFiles
{
public function execute(array $paths): array
{
try {
$ids = [];
foreach ($paths as $path) {
$response = Http::withHeaders([
'x-api-key' => config('anthropic.api_key'),
'anthropic-version' => '2023-06-01',
'anthropic-beta' => 'files-api-2025-04-14',
])->attach(
'file',
fopen($path, 'r'),
basename($path)
)->post(config('anthropic.base_url') . '/v1/files');
$data = $response->json();
if ($response->successful() && isset($data['id'])) {
$ids[] = $data['id'];
} else {
Log::error('Claude file upload failed', [
'path' => $path,
'response' => $data,
]);
}
}
return $ids;
}
catch (\Illuminate\Http\Client\ConnectionException $exception) {
$error = 'Failed to connect to Claude API';
throw new ConnectionErrorException(
$error,
$exception->getMessage(),
$exception->getTraceAsString()
);
}
catch (\Exception $exception) {
throw new MalformedRequestException(
'Unable to get correct response from Claude API: ' . $exception->getMessage()
);
}
}
}
@@ -0,0 +1,69 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Companies\Standards\Rules\CanFetchCompany;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Http\Resources\EInvoiceInfoResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchCompanyEInvoiceInfoLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Company E-Invoice Info',
'message' => 'You have successfully retrieved a Company E-Invoice Info'
];
}
/** @var CanFetchCompany */
private $canFetchCompany;
/** @var FetchesCompany */
private $fetchesCompany;
/**
* FetchCompanyEInvoiceInfoLogic constructor.
* @param CanFetchCompany $canFetchCompany
* @param FetchesCompany $fetchesCompany
*/
public function __construct(CanFetchCompany $canFetchCompany, FetchesCompany $fetchesCompany)
{
$this->canFetchCompany = $canFetchCompany;
$this->fetchesCompany = $fetchesCompany;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchCompany->passes();
$company = $this->fetchesCompany->execute(['id' => $request->route('id')]);
$eInvoiceInfo = $company->companyModules()->first()->addresses()->where('type', '=', AddressType::E_INVOICE)->latest()->first();
if($eInvoiceInfo){
$eInvoiceInfo->tin = $company->tin;
$eInvoiceInfo->msic_code = $company->msic_code;
$eInvoiceInfo->e_invoice = $company->e_invoice;
}
else{
return $this->response([]);
}
return $this->resourceResponse(new EInvoiceInfoResource($eInvoiceInfo));
}
}
@@ -0,0 +1,190 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Companies\Services\UpdatesCompany;
use App\Classes\Modules\Companies\Services\UpdatesCompanyDebtor;
use App\Classes\Modules\Addresses\Services\UpsertsAddress;
use App\Classes\Modules\Addresses\Services\FetchesDistrict;
use App\Classes\Modules\Companies\Services\UpdatesCompanyModuleName;
use App\Classes\Modules\Documents\Services\FetchesDocument;
use App\Classes\Modules\Documents\Services\UpdatesDocumentReference;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceInfo;
use App\Classes\Modules\Companies\Standards\Rules\CanUpdateCompany;
use App\Classes\Modules\Addresses\Standards\Rules\CanCreateAddress;
use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
use App\Classes\Modules\Companies\DataTransferObjects\CompanyObject;
use App\Classes\Modules\Companies\DataTransferObjects\UpdateCompanyDetailsDTO;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\ValueObjects\Constants\CompanyType;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Http\Resources\CompanyResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyDetailsLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Update Company Details',
'message' => 'You have successfully updated the Company Details'
];
}
/** @var CanUpdateCompany */
private $canUpdateCompany;
/** @var UpdatesCompany */
private $updatesCompany;
/** @var FetchesCompany */
private $fetchesCompany;
/** @var UpdatesCompanyDebtor */
private $updatesCompanyDebtor;
/** @var CanCreateAddress */
private $canCreateAddress;
/** @var FetchesDistrict */
private $fetchesDistrict;
/** @var UpsertsAddress */
private $upsertsAddress;
/** @var UpdatesCompanyEInvoiceInfo */
private $updatesCompanyEInvoiceInfo;
/** @var UpdatesCompanyModuleName */
private $updatesCompanyModuleName;
/** @var FetchesDocument */
private $fetchesDocument;
/** @var UpdatesDocumentReference */
private $updatesDocumentReference;
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFile;
/**
* UpdateCompanyDetailsLogic constructor.
* @param CanUpdateCompany $canUpdateCompany
* @param UpdatesCompany $updatesCompany
* @param FetchesCompany $fetchesCompany
* @param UpdatesCompanyDebtor $updatesCompanyDebtor
* @param CanCreateAddress $canCreateAddress
* @param FetchesDistrict $fetchesDistrict
* @param UpsertsAddress $upsertsAddress
* @param UpdatesCompanyEInvoiceInfo $updatesCompanyEInvoiceInfo;
* @param FetchesDocument $fetchesDocument
* @param UpdatesDocumentReference $updatesDocumentReference
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFile
*/
public function __construct(
CanUpdateCompany $canUpdateCompany,
UpdatesCompany $updatesCompany,
FetchesCompany $fetchesCompany,
UpdatesCompanyDebtor $updatesCompanyDebtor,
CanCreateAddress $canCreateAddress,
FetchesDistrict $fetchesDistrict,
UpsertsAddress $upsertsAddress,
UpdatesCompanyEInvoiceInfo $updatesCompanyEInvoiceInfo,
UpdatesCompanyModuleName $updatesCompanyModuleName,
FetchesDocument $fetchesDocument,
UpdatesDocumentReference $updatesDocumentReference,
CreatesDocument $createsDocument,
CreatesFiles $createsFile
)
{
$this->canUpdateCompany = $canUpdateCompany;
$this->updatesCompany = $updatesCompany;
$this->fetchesCompany = $fetchesCompany;
$this->updatesCompanyDebtor = $updatesCompanyDebtor;
$this->canCreateAddress = $canCreateAddress;
$this->fetchesDistrict = $fetchesDistrict;
$this->upsertsAddress = $upsertsAddress;
$this->updatesCompanyEInvoiceInfo = $updatesCompanyEInvoiceInfo;
$this->updatesCompanyModuleName = $updatesCompanyModuleName;
$this->fetchesDocument = $fetchesDocument;
$this->updatesDocumentReference = $updatesDocumentReference;
$this->createsDocument = $createsDocument;
$this->createsFile = $createsFile;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new UpdateCompanyDetailsDTO($request->all());
$object = new CompanyObject($dto->name, $dto->reference, $dto->type);
$this->canUpdateCompany->passes($object);
$company = $this->fetchesCompany->execute(['id' => $request->route('id')]);
$this->updatesCompanyModuleName->execute($company->companyModules()->first(), $object->getName());
//Update Name and Debtor, Type
$company = $this->updatesCompany->execute($company, $object);
if ($request->input('debtor') || $company->first()->debtor !== null) {
$this->updatesCompanyDebtor->execute($company, $request->input('debtor'));
}
//Update EInvoice Related Info
if($company->e_invoice){
$district = $this->fetchesDistrict->execute(['id' => $dto->districtId]);
$addObj = new AddressObject($dto->streetOne, $dto->streetTwo, $district->country_id, $dto->stateId, $district->id, $dto->postCode, AddressType::E_INVOICE, ApprovalStatus::APPROVED, 'E-Invoice');
$this->canCreateAddress->passes($addObj);
$this->upsertsAddress->execute($company->companyModules()->first(), $addObj, $dto->addressId);
$this->updatesCompanyEInvoiceInfo->execute($company, $dto->tin, $dto->msicCode);
}
//Update Identification Card / SSM Registration
if($dto->identificationId){
$document = $this->fetchesDocument->execute(['id' => $dto->identificationId]);
$this->updatesDocumentReference->execute($document, $dto->identificationReference);
}
else{
if($dto->identificationReference){
$pathToFile = base_path('resources/assets/images/ssm_ic_placeholder.png');
$mimeType = mime_content_type($pathToFile);
$fileContents = file_get_contents($pathToFile);
$base64 = base64_encode($fileContents);
$base64File = "data:$mimeType;base64,$base64";
$files = [$base64File];
/** @var Document $document */
$company = $this->fetchesCompany->execute(['id' => $dto->id]);
$object = new DocumentObject($company->type === CompanyType::COMPANY_BUSINESS ?
DocumentType::SSM_REGISTRATION : DocumentType::IDENTITY_CARD, $files,
$dto->identificationReference, ApprovalStatus::PENDING_VERIFICATION, 'identifications');
$document = $this->createsDocument->execute($company, $object);
$this->createsFile->execute($document, $object);
}
}
return $this->resourceResponse(new CompanyResource($company));
}
}
@@ -0,0 +1,116 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Addresses\Services\CreatesAddress;
use App\Classes\Modules\Addresses\Services\FetchesDistrict;
use App\Classes\Modules\Addresses\Standards\Rules\CanCreateAddress;
use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceInfo;
use App\Classes\Modules\Companies\DataTransferObjects\EInvoiceInfoDTO;
use App\Classes\Modules\Rules\Services\RuleEvaluator;
use App\Classes\Modules\Rules\Standards\Rules\CanPassEInvoicePromptedRule;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyEInvoiceInfoLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'EInvoice Info Update',
'message' => 'You have successfully updated company E-Invoice information'
];
}
/** @var CanCreateAddress */
private $canCreateAddress;
/** @var FetchesDistrict */
private $fetchesDistrict;
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/** @var CreatesAddress */
private $createsAddress;
/** @var RuleEvaluator */
private $ruleEvaluator;
/** @var UpdatesCompanyEInvoiceInfo */
private $updatesCompanyEInvoiceInfo;
/** @var CanPassEInvoicePromptedRule */
private $canPassEInvoicePromptedRule;
/**
* UpdateCompanyEInvoiceInfoLogic constructor.
* @param CanCreateAddress $canCreateAddress
* @param FetchesDistrict $fetchesDistrict
* @param FetchesCompanyModule $fetchesCompanyModule
* @param CreatesAddress $createsAddress
* @param RuleEvaluator $ruleEvaluator;
* @param UpdatesCompanyEInvoiceInfo $updatesCompanyEInvoiceInfo;
* @param CanPassEInvoicePromptedRule $canPassEInvoicePromptedRule
*/
public function __construct(CanCreateAddress $canCreateAddress, FetchesDistrict $fetchesDistrict, FetchesCompanyModule $fetchesCompanyModule, CreatesAddress $createsAddress, RuleEvaluator $ruleEvaluator, UpdatesCompanyEInvoiceInfo $updatesCompanyEInvoiceInfo, CanPassEInvoicePromptedRule $canPassEInvoicePromptedRule)
{
$this->canCreateAddress = $canCreateAddress;
$this->fetchesDistrict = $fetchesDistrict;
$this->fetchesCompanyModule = $fetchesCompanyModule;
$this->createsAddress = $createsAddress;
$this->ruleEvaluator = $ruleEvaluator;
$this->updatesCompanyEInvoiceInfo = $updatesCompanyEInvoiceInfo;
$this->canPassEInvoicePromptedRule = $canPassEInvoicePromptedRule;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
* @throws \App\Classes\Exceptions\CriteriaNotFulfilledException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new EInvoiceInfoDTO($request->all());
$result = $this->ruleEvaluator->evaluate([
$this->canPassEInvoicePromptedRule,
], $dto);
if ($result->failed()) {
throw new CriteriaNotFulfilledException("- " . implode("<br>- ", $result->messages()));
}
$district = $this->fetchesDistrict->execute(['id' => $dto->districtId]);
$object = new AddressObject($dto->streetOne, $dto->streetTwo, $district->country_id, $dto->stateId, $district->id, $dto->postCode, AddressType::E_INVOICE, ApprovalStatus::APPROVED, 'E-Invoice');
//Update Address
$this->canCreateAddress->passes($object);
$companyModule = $this->fetchesCompanyModule->execute(['id' => $dto->companyModuleId]);
$this->createsAddress->execute($companyModule, $object);
// create billing address if not exists
$billingAddress = $companyModule->addresses->where('type', AddressType::BILLING)->where('status', ApprovalStatus::APPROVED)->first();
if (!$billingAddress) {
$billingAddress = new AddressObject($dto->streetOne, $dto->streetTwo, $district->country_id, $dto->stateId, $district->id, $dto->postCode, AddressType::BILLING, ApprovalStatus::APPROVED, 'Billing Address');
$this->createsAddress->execute($companyModule, $billingAddress);
}
//Update tin, msic code
$this->updatesCompanyEInvoiceInfo->execute($companyModule->company, $dto->tin, $dto->msicCode);
return $this->response([]);
}
}
@@ -0,0 +1,62 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceRequest;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Companies\DataTransferObjects\EInvoiceRequestDTO;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyEInvoiceRequestChangeLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Updated EInvoice Request',
'message' => 'You have successfully updated company E-Invoice request'
];
}
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/** @var UpdatesCompanyEInvoiceRequest */
private $updatesCompanyEInvoiceRequest;
/**
* UpdateCompanyEInvoiceRequestChangeLogic constructor.
* @param FetchesCompanyModule $fetchesCompanyModule
* @param UpdatesCompanyEInvoiceRequest $updatesCompanyEInvoiceRequest
*/
public function __construct(FetchesCompanyModule $fetchesCompanyModule, UpdatesCompanyEInvoiceRequest $updatesCompanyEInvoiceRequest)
{
$this->fetchesCompanyModule = $fetchesCompanyModule;
$this->updatesCompanyEInvoiceRequest = $updatesCompanyEInvoiceRequest;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new EInvoiceRequestDTO($request->all());
$companyModule = $this->fetchesCompanyModule->execute(['id' => $dto->companyModuleId]);
if($companyModule->company->e_invoice === 1){
$this->updatesCompanyEInvoiceRequest->execute($companyModule->company, $dto->eInvoiceRequest);
}
return $this->response([]);
}
}
@@ -0,0 +1,59 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceRequest;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Companies\DataTransferObjects\EInvoiceRequestDTO;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyEInvoiceRequestLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Updated EInvoice Request',
'message' => 'You have successfully updated company E-Invoice request'
];
}
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/** @var UpdatesCompanyEInvoiceRequest */
private $updatesCompanyEInvoiceRequest;
/**
* UpdateCompanyEInvoiceRequestLogic constructor.
* @param FetchesCompanyModule $fetchesCompanyModule
* @param UpdatesCompanyEInvoiceRequest $updatesCompanyEInvoiceRequest
*/
public function __construct(FetchesCompanyModule $fetchesCompanyModule, UpdatesCompanyEInvoiceRequest $updatesCompanyEInvoiceRequest)
{
$this->fetchesCompanyModule = $fetchesCompanyModule;
$this->updatesCompanyEInvoiceRequest = $updatesCompanyEInvoiceRequest;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new EInvoiceRequestDTO($request->all());
$companyModule = $this->fetchesCompanyModule->execute(['id' => $dto->companyModuleId]);
$this->updatesCompanyEInvoiceRequest->execute($companyModule->company, $dto->eInvoiceRequest);
return $this->response([]);
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Classes\Modules\Companies\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class EInvoiceInfoDTO implements DataTransferObject
{
public string $tin;
public string $msicCode;
public int $districtId;
public int $stateId;
public int $companyModuleId;
public string $streetOne;
public string $streetTwo;
public string $postCode;
public function __construct(array $data)
{
$this->tin = (string) ($data['tin'] ?? '');
$this->msicCode = (string) ($data['msic_code'] ?? '');
$this->districtId = (int) ($data['district_id'] ?? 0);
$this->stateId = (int) ($data['state_id'] ?? 0);
$this->companyModuleId = (int) ($data['company_module_id'] ?? 0);
$this->streetOne = (string) ($data['street_one'] ?? '');
$this->streetTwo = (string) ($data['street_two'] ?? '');
$this->postCode = (string) ($data['post_code'] ?? '');
}
public function toArray(): array
{
return [
'tin' => $this->tin,
'msic_code' => $this->msicCode,
'district_id' => $this->districtId,
'state_id' => $this->stateId,
'company_module_id' => $this->companyModuleId,
'street_one' => $this->streetOne,
'street_two' => $this->streetTwo,
'post_code' => $this->postCode,
];
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Classes\Modules\Companies\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class EInvoiceRequestDTO implements DataTransferObject
{
public bool $eInvoiceRequest;
public int $companyModuleId;
public function __construct(array $data)
{
$this->eInvoiceRequest = $data['e_invoice_request'];
$this->companyModuleId = $data['company_module_id'];
}
public function toArray(): array
{
return [
'e_invoice_request' => $this->eInvoiceRequest,
'company_module_id' => $this->companyModuleId,
];
}
}
@@ -0,0 +1,72 @@
<?php
namespace App\Classes\Modules\Companies\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class UpdateCompanyDetailsDTO implements DataTransferObject
{
public int $id;
public string $name;
public string $debtor;
public string $reference;
public int $type;
public string $tin;
public string $msicCode;
public int $addressId;
public int $districtId;
public int $stateId;
public int $companyId;
public string $streetOne;
public string $streetTwo;
public string $postCode;
public string $identificationReference;
public int $identificationId;
public function __construct(array $data)
{
$this->id = (int) ($data['id'] ?? 0);
$this->name = (string) ($data['name'] ?? '');
$this->debtor = (string) ($data['debtor'] ?? '');
$this->reference = (string) ($data['reference'] ?? '');
$this->type = (int) ($data['type'] ?? 0);
$this->tin = (string) ($data['tin'] ?? 0);
$this->msicCode = (string) ($data['msic_code'] ?? '');
$this->addressId = (int) ($data['address_id'] ?? 0);
$this->districtId = (int) ($data['district_id'] ?? 0);
$this->stateId = (int) ($data['state_id'] ?? 0);
$this->companyId = (int) ($data['company_id'] ?? 0);
$this->streetOne = (string) ($data['street_one'] ?? '');
$this->streetTwo = (string) ($data['street_two'] ?? '');
$this->postCode = (string) ($data['post_code'] ?? '');
$this->identificationReference = (string) ($data['identification_reference'] ?? '');
$this->identificationId = (int) ($data['identification_id'] ?? 0);
}
public function toArray(): array
{
return [
'id' => $this->id,
'name' => $this->name,
'debtor' => $this->debtor,
'reference' => $this->reference,
'type' => $this->type,
'tin' => $this->tin,
'msic_code' => $this->msicCode,
'address_id' => $this->addressId,
'district_id' => $this->districtId,
'state_id' => $this->stateId,
'company_id' => $this->companyId,
'street_one' => $this->streetOne,
'street_two' => $this->streetTwo,
'post_code' => $this->postCode,
'identification_reference' => $this->identificationReference,
'identification_id' => $this->identificationId,
];
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Classes\Modules\Companies\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Models\Company;
class UpdatesCompanyEInvoiceInfo extends AbstractUpdateRecord
{
/**
* @param Company $model
* @param string $tin
* @param string $msicCode
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Company $model, string $tin, string $msicCode)
{
$model->tin = $tin;
$model->msic_code = $msicCode;
return $this->handler($model);
}
}
@@ -0,0 +1,35 @@
<?php
namespace App\Classes\Modules\Companies\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Models\Company;
class UpdatesCompanyEInvoiceRequest extends AbstractUpdateRecord
{
/**
* @param Company $model
* @param bool $eInvoice
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Company $model, bool $eInvoice)
{
if($eInvoice){
if (is_null($model->e_invoice_requested_at)) {
if($eInvoice){
$model->e_invoice_requested_at = now();
}
}
$model->e_invoice = 1;
}
else{
$model->e_invoice_requested_at = null;
$model->e_invoice = 0;
}
return $this->handler($model);
}
}
@@ -2,19 +2,27 @@
namespace App\Classes\Modules\Exports\Services;
use App\Models\CompanyConnection;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use App\Classes\General\Eloquent\ApplyFiltersToQuery;
use App\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ExportsAllCustomersInfoForLarkSystem implements WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize, FromQuery
class ExportsAllCustomersInfoForLarkSystem implements FromQuery, WithMapping, WithHeadings, ShouldAutoSize
{
use Exportable;
public function __construct() {}
protected $deduplicateMarking;
protected $request;
public function __construct(Request $request, $deduplicateMarking = true)
{
$this->deduplicateMarking = $deduplicateMarking;
$this->request = $request;
}
public function headings(): array
{
@@ -25,33 +33,54 @@ class ExportsAllCustomersInfoForLarkSystem implements WithHeadings, WithHeadingR
'Email',
'Registration Date',
'Last Order Date',
'Debtor Code',
'Credit Term Customer',
'Custom Segments',
];
}
public function query()
{
return (new ApplyFiltersToQuery())->execute(Company::query(), [
'has_business_module_type' => 1,
$baseQuery = CompanyConnection::has('invitee.company');
if ($this->deduplicateMarking) {
$baseQuery->whereIn('id', function ($sub) {
$sub->selectRaw('min(id)')
->from('company_connections')
->groupBy('invitee_reference');
});
}
return $baseQuery->with([
'invitee.company.contacts',
'invitee.company.companyModules.employees',
'segments'
]);
}
public function map($company): array
public function map($connection): array
{
$company_module = $company->companyModules()->first();
$marking = $company_module->getMarking();
$employees = $company_module->employees()->first();
$company = optional(optional($connection)->invitee)->company;
$companyModule = optional($company)->companyModules->first();
$employee = optional($companyModule)->employees->first();
$contact = optional($company)->contacts->first();
$data = [
$marking = $connection->invitee_reference;
$creditTermCustomer = $connection->is_credit_term ? 'YES' : 'NO';
$employeeEmail = optional($employee)->email ?? '';
$contactPhone = optional($contact)->phone ?? '';
$segments = optional($connection->segments)->pluck('name')->implode(', ') ?: '';
return [
$marking,
$company->name,
$company->contacts()->first()->phone ?? '',
$employees?->email ?? '',
$company->created_at,
$company->updated_at,
$company_module->connections()->first()->segments()->pluck('name')->implode(', ')
optional($company)->name ?? '',
$contactPhone,
$employeeEmail,
optional($company)->created_at ? $company->created_at->toDateString() : '',
optional($company)->updated_at ? $company->updated_at->toDateString() : '',
optional($company)->debtor ?? '',
$creditTermCustomer,
$segments,
];
return $data;
}
}
@@ -51,7 +51,7 @@ class ExportsArrivedParcel implements WithHeadings, WithHeadingRow, WithMapping,
'transports'
])
->where('type', '=', 1)
->where('status', '=', 2)
// ->where('status', '=', 2)
->where('owner_type', Order::class)
->whereBetween('created_at', [Carbon::now()->subMonths(12), Carbon::now()]); //Limit, 'expensive' query
@@ -0,0 +1,105 @@
<?php
namespace App\Classes\Modules\Exports\Services;
use App\Classes\General\Helper;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Company;
use Carbon\Carbon;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Illuminate\Support\Facades\Log;
class ExportsCompanies implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
{
use Exportable;
protected $startDate;
protected $endDate;
public function __construct($startDate = null, $endDate = null) {
$this->startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1);
$this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now();
}
public function headings(): array
{
return [
'TIN',
'IdentityNo',
'Name',
'IdentityType',
'TaxClassification',
'MSICCode',
'BusinessActivityDesc',
'DebtorCode',
'TradeName',
'Address',
'PostCode',
'Phone',
'EmailAddress',
'City',
'CountryCode',
'StateCode'
];
}
/**
* @return \Illuminate\Support\Collection|mixed
*/
public function query()
{
return Company::whereBetween('e_invoice_requested_at', [$this->startDate, $this->endDate]);
}
/**
* @param Company $company
*
* @return array
*/
public function map($company): array
{
$companyModule = $company->companyModules()->first();
$employee = $companyModule->employees()->first();
$identityNo = $company->documents->where('document_type', DocumentType::IDENTITY_CARD)->first();
$identityType = DocumentType::IDENTITY_CARD;
if(!$identityNo){
$identityNo = $company->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first();
$identityType = DocumentType::SSM_REGISTRATION;
}
$identityReference = "";
if($identityNo){
$identityReference = preg_replace('/\s*\(.*?\)/', '', $identityNo->reference);
}
$address = $companyModule->addresses()->where('type', AddressType::E_INVOICE)->latest()->first();
if(!$address){
$address = $companyModule->addresses()->where('type', AddressType::BILLING)->first();
}
return [
$company->tin, // 'TIN',
$identityReference, // 'IdentityNo',
$company->name, // 'Name',
$identityType === DocumentType::IDENTITY_CARD ? 'MyKAD' : '', // 'IdentityType',
$company->type !== null ? (string) $company->type : '0', // 'TaxClassification',
$company->msic_code, // 'MSICCode',
$company->msic_code ? Helper::getLHDNMsicDescriptionByCode($company->msic_code) : '', // 'BusinessActivityDesc',
$company->debtor, // 'DebtorCode',
$company->name, // 'TradeName',
$address ? $address->street_one . ',' . $address->street_two : '',// 'Address',
$address ? $address->postcode : '', // 'PostCode',
$company->contacts()->first() ? $company->contacts()->first()->phone : '', // 'Phone',
$employee ? $employee->email : '', // 'EmailAddress',
$address ? $address->district()->first()->name : '', // 'City',
'MYS', // 'CountryCode',
$address ? Helper::getLHDNStateCodeByName($address->state()->first()->name) : '', // 'StateCode'
];
}
}
@@ -68,6 +68,8 @@ class ExportsNullDebtors implements FromQuery, WithHeadings, WithHeadingRow, Wit
public function map($company): array
{
$marking = $company->companyModules()->where('type', BusinessType::IMPORTER)->first()->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference;
$companyModule = $company->companyModules()->first();
$employee = $companyModule->employees()->first();
return [
'<<New>>',
@@ -87,7 +89,7 @@ class ExportsNullDebtors implements FromQuery, WithHeadings, WithHeadingRow, Wit
'',
'',
'',
'',//EmailAddress
$employee->email,//EmailAddress
'',
'',
'',
@@ -0,0 +1,103 @@
<?php
namespace App\Classes\Modules\Exports\Services;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Models\Transaction;
use App\Models\Wallet;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class ExportsReceivePaymentDepositEntryReport implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
{
use Exportable;
protected $startDate;
protected $endDate;
public function __construct($startDate = null, $endDate = null) {
$this->startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1);
$this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now();
}
public function headings(): array
{
return [
'DocNo',
'DocDate',
'DebtorCode',
'Description',
'DeptNo',
'DepositPaymentMethod',
'PaymentMethod',
'PaymentAmt',
];
}
/**
* @return \Illuminate\Support\Collection|mixed
*/
public function query()
{
$type = TransactionType::PAYMENT;
$query = Transaction::query();
// $query->where('owner_type', '!=', Wallet::class);
$query->where('type', $type);
$query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
$query->whereBetween('created_at', [$this->startDate, $this->endDate]);
return $query;
}
/**
* @param Transaction $transaction
* @return array
*/
public function map($transaction): array
{
$formattedDocumentDate = Carbon::parse($transaction->created_at)->format('m/d/Y');
$order = null;
$owner = $transaction->owner;
if(!$owner) return[];
if($owner instanceof Wallet){
$company = $owner->owner->company;
}
else{
$order = $owner->owner->owner;
$company = $order->companyModule->company;
}
$paymentMethod = '';
if($transaction->payment_method == PaymentMethodType::WALLET){
$paymentMethod = 'WALLET DEPOSIT-IZYIM';
if($owner instanceof Transaction){
return[];
}
}
else{
$paymentMethod = 'MBB';
}
return [
'<<New>>', //DocNo
$formattedDocumentDate, //DocDate
$company ? $company->debtor : '', //DebtorCode
$order ? $order->reference : '', //Description
'C', //DeptNo
'SALES DEPOSIT - IZYI', //DepositPaymentMethod
$paymentMethod, //PaymentMethod
number_format($transaction->amount, 2), //PaymentAmt
];
}
}
@@ -0,0 +1,111 @@
<?php
namespace App\Classes\Modules\Exports\Services;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\KVPKey;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Models\Transaction;
use App\Models\Wallet;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class ExportsReceivePaymentForOrderReport implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
{
use Exportable;
protected $startDate;
protected $endDate;
public function __construct($startDate = null, $endDate = null) {
$this->startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1);
$this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now();
}
public function headings(): array
{
return [
'DocNo',
'Docdate',
'DebtorCode',
'Description',
'DeptNo',
'PaymentMethod',
'PaymentAmt',
'KnockOffDocType',
'KnockOffDocNo',
'KnockOffAmt',
];
}
/**
* @return \Illuminate\Support\Collection|mixed
*/
public function query()
{
$type = TransactionType::PAYMENT;
$query = Transaction::query();
// $query->where('owner_type', '!=', Wallet::class);
$query->where('type', $type);
$query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
$query->whereBetween('created_at', [$this->startDate, $this->endDate]);
return $query;
}
/**
* @param Transaction $transaction
* @return array
*/
public function map($transaction): array
{
$autoCountSalesInvoiceId = null;
$formattedDocumentDate = Carbon::parse($transaction->created_at)->format('m/d/Y');
$order = null;
$invoice = null;
$owner = $transaction->owner;
if($owner instanceof Wallet){
$company = $owner->company;
}
else{
$invoice = $transaction->owner;
$order = $invoice->owner->owner;
$company = $order->companyModule->company;
}
if($invoice){
$metadata = $invoice->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if($metadata){
$autoCountSalesInvoiceId = $metadata->value;
}
}
if($transaction->payment_method == PaymentMethodType::WALLET){
if($owner instanceof Wallet){
return[];
}
}
return [
'<<New>>', //DocNo
$formattedDocumentDate, //DocDate
$company ? $company->debtor : '', //DebtorCode
'Payment for ' . $autoCountSalesInvoiceId ?? '', //Description
'C', //DeptNo
'SALES DEPOSIT - IZYI', //PaymentMethod
number_format($transaction->amount, 2), //PaymentAmt
'RI', //KnockOffDocType
$autoCountSalesInvoiceId ?? '', //KnockOffDocNo
number_format($transaction->amount, 2), //KnockOffAmt
];
}
}
@@ -0,0 +1,210 @@
<?php
namespace App\Classes\Modules\Exports\Services;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\KVPKey;
use App\Models\Transaction;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class ExportsSalesInvoicesReport implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
{
use Exportable;
protected $startDate;
protected $endDate;
protected $isUnpaid;
public function __construct($startDate = null, $endDate = null, $isUnpaid = false) {
$this->startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1);
$this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now();
$this->isUnpaid = $isUnpaid;
}
public function headings(): array
{
return [
'DocNo',
'DocDate',
'DebtorCode',
'Ref',
'ShipInfo',
'AccNo',
'DetailDescription',
'FurtherDescription',
'Classification',
'ProjNo',
'DeptNo',
'Qty',
'UnitPrice',
'TaxCode',
'TaxableAmt',
'TaxRate',
'SubmitEinvoice',
'ConsolidatedEInvoice',
// 'PaymentDate',
];
}
/**
* @return \Illuminate\Support\Collection|mixed
*/
public function query()
{
$start_date = $this->startDate;
$end_date = $this->endDate;
$query = Transaction::with([
'transactionDetails',
'transactions',
'attributesKVP',
'owner.containers',
'owner.owner.companyModule.company.contacts',
'owner.owner.companyModule.inviters',
'owner.owner.companyModule.employees'
]);
// if($this->isUnpaid){
// $approvalStatus = ApprovalStatus::COMPLETED;
// $query->whereIn('type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])
// ->whereNotIn('status', [$approvalStatus])
// ->whereBetween('created_at', [$start_date, $end_date]);
// }
// else{
// $approvalStatus = ApprovalStatus::COMPLETED;
// $query->whereIn('type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])
// ->where('status', $approvalStatus)
// ->whereBetween('created_at', [$start_date, $end_date]);
// $query->whereHas('transactions', function($transaction) {
// $transaction->where('type', TransactionType::PAYMENT)
// ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
// });
// }
if($this->isUnpaid){
$approvalStatus = ApprovalStatus::COMPLETED;
$query->whereIn('type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])
->whereNotIn('status', [$approvalStatus])
->whereBetween('created_at', [$start_date, $end_date]);
}
else{
//This will query everything both paid and unpaid unlike previously paid only
$query->whereIn('type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])
->whereBetween('created_at', [$start_date, $end_date]);
}
return $query;
}
public function map($transaction): array
{
$container = $transaction->owner ? $transaction->owner->containers->first() : null;
$packingList = $transaction->owner;
if(!$packingList) return[];
$order = $packingList->owner;
$company = $order->companyModule->company;
// if(!$this->isUnpaid){
// $lastPaymentTransaction = $transaction->transactions
// ->whereIn('type', [TransactionType::PAYMENT, TransactionType::TOP_UP])
// ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
// ->sortByDesc('created_at')
// ->first();
// $documentDate = Carbon::parse($lastPaymentTransaction->created_at);
// if($company->e_invoice === 1){
// $documentDate = $documentDate->copy()->endOfMonth();
// }
// $formattedDocumentDate = Carbon::parse($documentDate)->format('m/d/Y');
// }
$documentDate = Carbon::parse($transaction->created_at);
if($company->e_invoice === 1){
$documentDate = $documentDate->copy()->endOfMonth();
}
$formattedDocumentDate = Carbon::parse($documentDate)->format('m/d/Y');
// if($transaction->type === TransactionType::STORAGE_INVOICE){
// $shippingTransactionDetails = $transaction->transactionDetails->where('reference', 'STORAGE_FEE')->first();
// }
// else{
// $shippingTransactionDetails = $transaction->transactionDetails->where('reference', 'SHIPPING_FEE')->first();
// }
$marking = $order->companyModule->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference;
// $contact = $order->companyModule->company->contacts->first();
// $userName = $order->companyModule->employees->first();
// $link = route('customer.payment-and-billing', $marking);
$furtherDescription = '';
foreach ($transaction->transactionDetails as $item){
if($item->reference === 'SHIPPING_FEE')
$furtherDescription .= str_replace('X1 Freight Service Charge<br>', '', $item->name)."\n";
elseif($item->reference === 'OVER_WEIGHT_CHARGES')
$furtherDescription .= $item->name.' '.$item->quantity.' CBM'."\n";
elseif($item->reference === 'MIN_CBM_CHARGES')
$furtherDescription .= $item->name.' '.$item->quantity.' CBM'."\n";
elseif($item->reference === 'STORAGE_FEE')
$furtherDescription .= str_replace('<br>', ' | ', $item->name).' '."\n";
else
$furtherDescription .= $item->name.' '.$item->quantity.' X '.$item->price."\n";
}
$transactionDetails = $transaction->transactionDetails;
$firstItem = true;
$docNo = '<<New>>';
$firstItem = true;
if($transaction){
$transactionKVP = $transaction->attributesKVP->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if($transactionKVP){
$docNo = $transactionKVP->value;
}
}
$rows = [];
foreach ($transactionDetails as $detail) {
$rows[] = [
$firstItem ? $docNo : '', //DocNo
$formattedDocumentDate ?? '', //DocDate
$company->debtor, //DebtorCode
$transaction->bill_no, //Ref
$order->reference, //ShipInfo
'500-0000', //AccNo
'SERVICE OR ITEM :', //DetailDescription
str_replace('<br>', ' ', $detail->name), //FurtherDescription
'022', //Classification
$container->reference, //ProjNo
'C ', //DeptNo
$detail->quantity, //Qty
$detail->price, //UnitPrice
floatval($detail->tax_percentage) > 0 ? 'SV-6' : '', //TaxCode
floatval($detail->tax_percentage) > 0 ? number_format($detail->amount, 2) : '0.00', //TaxableAmt
$detail->tax_percentage, //TaxRate
$firstItem ? 'T' : '', //SubmitEinvoice
$company->e_invoice === 1 ? 'F' : 'T', //ConsolidatedEInvoice
// $transaction->transactions()->where('type', TransactionType::PAYMENT)->first()->updated_at->format('m/d/Y'), //PaymentDate
];
if($firstItem) {
$firstItem = false;
}
}
return $rows;
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Classes\Modules\Imports\ControllersLogic;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Imports\Services\AutoCountDataImport;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
class ImportExcelLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Import Excel',
'message' => 'You have successfully imported data from excel file'
];
}
/**
* @param Request $request
* @return JsonResponse
* @throws MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$result = [];
$reportType = $request->input('report_type');
$object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports');
$files = $object->getFiles();
if (count($files) > 1) {
throw new MalformedRequestException('Import function can only process one file at a time.');
}
foreach ($files as $file) {
$filePath = json_decode($file)->file_info->original->file;
$import = new AutoCountDataImport($reportType);
Excel::import($import, $filePath);
}
return $this->response($result);
}
}
@@ -0,0 +1,85 @@
<?php
namespace App\Classes\Modules\Imports\Services;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Jobs\Commands\V2\ProcessSalesInvoiceReportV2CommandJob;
use App\Classes\Jobs\Commands\V2\ProcessPaymentReportV2CommandJob;
use Illuminate\Support\Facades\Log;
class AutoCountDataImport implements ToCollection, WithHeadingRow, WithChunkReading
{
protected $reportType;
public function __construct($reportType)
{
$this->reportType = $reportType;
}
public function headingRow(): int
{
return 1;
}
/**
* @param Collection $collection
*/
public function collection(Collection $collection)
{
static $headerProcessed = false;
foreach ($collection as $row) {
if (!$headerProcessed) {
$header = $row->keys()->map(fn($h) => strtolower(trim($h)))->toArray();
$this->validateHeader($header, $this->reportType);
$headerProcessed = true;
}
if ($this->reportType === 'Sales Invoice Report') {
ProcessSalesInvoiceReportV2CommandJob::dispatch($row->toArray());
}
elseif ($this->reportType === '11R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]') {
ProcessPaymentReportV2CommandJob::dispatch($row->toArray());
}
else{
throw new MalformedRequestException('Cannot process report type: ' . $this->reportType);
}
}
}
public function chunkSize(): int
{
return 1000;
}
private function validateHeader(array $header, String $reportType)
{
$optionalColumn = 'einvoicevalidationlink';
$salesInvoiceHeader =
['docno', 'docdate', 'debtorcode', 'ref',
'shipinfo', 'accno', 'detaildescription', 'furtherdescription', 'classification', 'projno', 'deptno',
'qty', 'unitprice', 'taxcode', 'taxableamt', 'taxrate', 'submiteinvoice', 'consolidatedeinvoice'];
$paymentReportHeader = [
'docno',
'docdate',
'debtorcode',
'description',
'paymentmethod',
'paymentamt',
'knockoffdocno'
];
if ($reportType === 'Sales Invoice Report' &&
$header !== $salesInvoiceHeader &&
$header !== [...$salesInvoiceHeader, $optionalColumn]) {
throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.');
}
elseif ($reportType === '11R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]' && $header !== $paymentReportHeader) {
throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.');
}
}
}
@@ -0,0 +1,85 @@
<?php
namespace App\Classes\Modules\Orders\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Jobs\Commands\V2\ProcessTransactionForEInvoiceV2CommandJob;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Log;
class CreateBatchProcessingAutoCountImportLogic extends AbstractControllerLogic
{
protected int $processedCount = 0;
/**
* @return array
*/
protected function notification(): array
{
return [
'title' => 'Generate E-Invoices',
'message' => sprintf(
'You have successfully submitted %d transaction%s for E-Invoices processing.',
$this->processedCount,
$this->processedCount === 1 ? '' : 's'
),
];
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request): JsonResponse
{
$validated = $request->validate([
'startDate' => 'nullable|date_format:d-m-Y',
'endDate' => 'nullable|date_format:d-m-Y|after_or_equal:startDate',
]);
$startDate = null;
$endDate = null;
$startDate = isset($validated['startDate']) && $validated['startDate']
? Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay()
: Carbon::now()->startOfMonth()->startOfDay();
$endDate = isset($validated['endDate']) && $validated['endDate']
? Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay()
: Carbon::now()->endOfMonth()->endOfDay();
$query = Transaction::query();
$query->whereIn('type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
// $transactions = $query->whereHas('transactions', function($transaction) use ($startDate, $endDate) {
// $transaction->where('type', TransactionType::PAYMENT)
// ->whereBetween('updated_at', [$startDate, $endDate])
// ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
// })->get();
$transactions = $query->whereBetween('created_at', [$startDate, $endDate])->get();
$count = 0;
foreach ($transactions as $transaction) {
ProcessTransactionForEInvoiceV2CommandJob::dispatch($transaction);
// $count = $count + 1;
// if($count > 15){
// break;
// }
}
$this->processedCount = count($transactions);
return $this->resourceResponse(JsonResource::collection(collect([])));
}
}
@@ -6,13 +6,13 @@ namespace App\Classes\Modules\Orders\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\Orders\Standards\Rules\CanFetchOrder;
use App\Http\Resources\OrderPackagesBaseResource;
use App\Http\Resources\OrderPackagesDeprecatedResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
/**
* @deprecated This class is deprecated and should not be used.
* Use `FetchOrderPackagesV2Logic` instead or write a new one based on FetchOrderPackagesV2Logic
* Use `FetchOrderPackagesReceivedV2Logic` instead or write a new one based on FetchOrderPackagesReceivedV2Logic
*/
class FetchOrderPackagesLogic extends AbstractControllerLogic
{
@@ -74,7 +74,7 @@ class FetchOrderPackagesLogic extends AbstractControllerLogic
$query->include_packages_received = $filters['include_packages_received'];
}
return $this->resourceResponse(new OrderPackagesBaseResource($query));
return $this->resourceResponse(new OrderPackagesDeprecatedResource($query));
}
@@ -0,0 +1,59 @@
<?php
namespace App\Classes\Modules\Orders\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\Orders\Standards\Rules\CanFetchOrder;
use App\Http\Resources\OrderPackagesReceivedResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchOrderPackagesReceivedV2Logic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Order Packages Received',
'message' => 'You have successfully retrieved an order packages'
];
}
/** @var CanFetchOrder */
private $canFetchOrder;
/** @var FetchesOrder */
private $fetchesOrder;
/**
* FetchOrderPackagesReceivedV2Logic constructor.
* @param CanFetchOrder $canFetchOrder
* @param FetchesOrder $fetchesOrder
*/
public function __construct(CanFetchOrder $canFetchOrder, FetchesOrder $fetchesOrder)
{
$this->canFetchOrder = $canFetchOrder;
$this->fetchesOrder = $fetchesOrder;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchOrder->passes();
$query = $this->fetchesOrder->execute(['reference' => $request->route('id'), 'with_packing_lists' => true]);
//Can refer FetchOrderPackagesLogic for different type of OrderPackages Resources
return $this->resourceResponse(new OrderPackagesReceivedResource($query));
}
}
@@ -6,10 +6,11 @@ namespace App\Classes\Modules\Orders\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\Orders\Standards\Rules\CanFetchOrder;
use App\Http\Resources\OrderPackagesReceivedResource;
use App\Http\Resources\OrderPackagesResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchOrderPackagesV2Logic extends AbstractControllerLogic
{
@@ -49,11 +50,7 @@ class FetchOrderPackagesV2Logic extends AbstractControllerLogic
public function logic(Request $request) : JsonResponse
{
$this->canFetchOrder->passes();
$query = $this->fetchesOrder->execute(['reference' => $request->route('id'), 'with_packing_lists' => true]);
//Can refer FetchOrderPackagesLogic for different type of OrderPackages Resources
return $this->resourceResponse(new OrderPackagesReceivedResource($query));
return $this->resourceResponse(new OrderPackagesResource($query));
}
}
@@ -6,7 +6,7 @@ namespace App\Classes\Modules\Orders\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\Orders\Standards\Rules\CanFetchOrder;
use App\Http\Resources\OrderV2Resource;
use App\Http\Resources\FetchOrderResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -48,7 +48,6 @@ class FetchOrderV2Logic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchOrder->passes();
$query = $this->fetchesOrder->execute(['reference' => $request->route('id'), 'with_packing_lists' => true]);
@@ -56,9 +55,6 @@ class FetchOrderV2Logic extends AbstractControllerLogic
if($request->input('storages')){
$query->storages = $request->input('storages'); //from middleware
}
return $this->resourceResponse(new OrderV2Resource($query));
return $this->resourceResponse(new FetchOrderResource($query));
}
}
@@ -8,7 +8,6 @@ use App\Classes\Modules\Orders\Services\ListsOrders;
use App\Classes\Modules\Orders\Standards\Rules\CanListOrders;
use App\Classes\ValueObjects\Constants\OrderType;
use App\Http\Resources\OrderBaseResource;
use App\Http\Resources\OrderV2Resource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -65,9 +64,5 @@ class ListOrdersV2Logic extends AbstractControllerLogic
}
return $this->collectionResponse(OrderBaseResource::collection($query));
//return $this->collectionResponse(OrderV2Resource::collection($query));
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\Exceptions\ResourceNotFoundException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Jobs\Commands\V2\YD\FetchPackingListsFromYdPortalV2CommandJob;
use App\Classes\Modules\PackingLists\Services\FetchesPackingList;
use App\Classes\Modules\Orders\Services\FetchesOrder;
@@ -23,9 +24,11 @@ use App\Classes\ValueObjects\Constants\OrderRoleTypes;
use App\Classes\Modules\Steps\DataTransferObjects\StepsObject;
use App\Http\Resources\PackingListResource;
use Carbon\Carbon;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class AssignPackingListOrderLogic extends AbstractControllerLogic
{
@@ -162,7 +165,43 @@ class AssignPackingListOrderLogic extends AbstractControllerLogic
}
// Update Packing Lists' packages info,
// Important for markup 'No Extra Centimeter Charged' reevaluation as a result of packing list is now 'Claimed' to an order (before this was Unclaimed Packing Lists)
// See CreatePackageProcessor.php
$jobs1 = $this->fetchPackingListsFromYdPortalV2CommandJobs();
foreach ($jobs1 as $index => $job) {
dispatch($job)->delay(now()->addSeconds($index * 2));
}
return $this->resourceResponse(new PackingListResource($warehouse_packing_list));
}
private function fetchPackingListsFromYdPortalV2CommandJobs(){
$jobs = [];
$from = 0;
$to = 10;
$count = 0;
for ($x = $from; $x <= $to; $x++) {
$startDate = Carbon::today()->subDays($x);
$startLimit = Carbon::parse('01-12-2021');
if($startDate->isBefore($startLimit)){
$startDate = $startLimit;
}
$endDate = Carbon::today()->subDays($x - 1);
$jobs[] = new FetchPackingListsFromYdPortalV2CommandJob($startDate, $endDate);
Log::info('(AssignPackingListOrderLogic) Dispatched FetchPackingListsFromYdPortalV2CommandJob for start date: ' . $startDate . ', end date: ' . $endDate);
$count++;
}
Log::info('(AssignPackingListOrderLogic) Total FetchPackingListsFromYdPortalV2CommandJob dispatched: ' . $count);
return $jobs;
}
}
@@ -0,0 +1,56 @@
<?php
namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\PackingLists\Standards\Rules\CanListPackingLists;
use App\Http\Resources\PackingListForWarehouseResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListPackingListsForWarehouseLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved PackingLists for Warehouse',
'message' => 'You have successfully retrieved a list of PackingLists for warehouse'
];
}
/** @var CanListPackingLists */
private $canListPackingLists;
/** @var ListsPackingLists */
private $listsPackingLists;
/**
* ListPackingListsForWarehouseLogic constructor.
* @param CanListPackingLists $canListPackingLists
* @param ListsPackingLists $listsPackingLists
*/
public function __construct(CanListPackingLists $canListPackingLists, ListsPackingLists $listsPackingLists)
{
$this->canListPackingLists = $canListPackingLists;
$this->listsPackingLists = $listsPackingLists;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canListPackingLists->passes();
$query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($request->input('filters')));
return $this->collectionResponse(PackingListForWarehouseResource::collection($query));
}
}
@@ -6,7 +6,6 @@ namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\PackingLists\Standards\Rules\CanListPackingLists;
use App\Http\Resources\PackingListBaseResource;
use App\Http\Resources\PackingListResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
@@ -52,57 +51,7 @@ class ListPackingListsLogic extends AbstractControllerLogic
public function logic(Request $request) : JsonResponse
{
$this->canListPackingLists->passes();
$query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($request->input('filters')));
$data = json_encode($request->input('storages'));
Log::info("ListPackingListsLogic storages A");
// if($request->input('storages')){
// Log::info("ListPackingListsLogic storages B");
// foreach ($query->items() as $item) {
// $item['storages'] = $request->input('storages');
// }
// return $this->collectionResponse(PackingListWithStorageResource::collection($query));
// }
$filters = json_decode($request->input('filters'), true);
$useNew = false;
foreach ($query->items() as $item) {
//from middleware
if($request->input('storages')){
$item['storages'] = $request->input('storages');
}
//from front end component
if(isset($filters['include_packages'])){
//'include_packages' filter is an attempt to reduce the request-response time to only load basic information unless explicitly indicated to be included
$item['include_packages'] = $filters['include_packages'];
$useNew = true;
}
if(isset($filters['include_receive_packing_list'])){
//'include_receive_packing_list' filter is an attempt to reduce the request-response time to only load basic information unless explicitly indicated to be included
$item['include_receive_packing_list'] = $filters['include_receive_packing_list'];
$useNew = true;
}
if(isset($filters['include_shipping_transaction'])){
$item['include_shipping_transaction'] = $filters['include_shipping_transaction'];
$useNew = true;
}
if(isset($filters['include_suspended_invoice'])){
$item['include_suspended_invoice'] = $filters['include_suspended_invoice'];
$useNew = true;
}
}
if($useNew){
return $this->collectionResponse(PackingListBaseResource::collection($query));
}
//Fallback
return $this->collectionResponse(PackingListResource::collection($query));
}
}
@@ -0,0 +1,63 @@
<?php
namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\PackingLists\Standards\Rules\CanListPackingLists;
use App\Http\Resources\PackingListPaidInvoiceResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ListPackingListsPaidInvoiceLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '(Paid Invoice) Retrieved PackingLists',
'message' => 'You have successfully retrieved a list of PackingLists'
];
}
/** @var CanListPackingLists */
private $canListPackingLists;
/** @var ListsPackingLists */
private $listsPackingLists;
/**
* ListPackingListsPaidInvoiceLogic constructor.
* @param CanListPackingLists $canListPackingLists
* @param ListsPackingLists $listsPackingLists
*/
public function __construct(CanListPackingLists $canListPackingLists, ListsPackingLists $listsPackingLists)
{
$this->canListPackingLists = $canListPackingLists;
$this->listsPackingLists = $listsPackingLists;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canListPackingLists->passes();
$query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($request->input('filters')));
foreach ($query->items() as $item) {
//from middleware
if($request->input('storages')){
$item['storages'] = $request->input('storages');
}
}
return $this->collectionResponse(PackingListPaidInvoiceResource::collection($query));
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\PackingLists\Standards\Rules\CanListPackingLists;
use App\Http\Resources\PackingListPendingApprovalResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ListPackingListsPendingApprovalLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '(Pending Approval) Retrieved PackingLists',
'message' => 'You have successfully retrieved a list of PackingLists'
];
}
/** @var CanListPackingLists */
private $canListPackingLists;
/** @var ListsPackingLists */
private $listsPackingLists;
/**
* ListPackingListsPendingApprovalLogic constructor.
* @param CanListPackingLists $canListPackingLists
* @param ListsPackingLists $listsPackingLists
*/
public function __construct(CanListPackingLists $canListPackingLists, ListsPackingLists $listsPackingLists)
{
$this->canListPackingLists = $canListPackingLists;
$this->listsPackingLists = $listsPackingLists;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canListPackingLists->passes();
$query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($request->input('filters')));
return $this->collectionResponse(PackingListPendingApprovalResource::collection($query));
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\PackingLists\Standards\Rules\CanListPackingLists;
use App\Http\Resources\PackingListPendingInvoiceResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ListPackingListsPendingInvoiceLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '(Pending Invoice) Retrieved PackingLists',
'message' => 'You have successfully retrieved a list of PackingLists'
];
}
/** @var CanListPackingLists */
private $canListPackingLists;
/** @var ListsPackingLists */
private $listsPackingLists;
/**
* ListPackingListsPendingInvoiceLogic constructor.
* @param CanListPackingLists $canListPackingLists
* @param ListsPackingLists $listsPackingLists
*/
public function __construct(CanListPackingLists $canListPackingLists, ListsPackingLists $listsPackingLists)
{
$this->canListPackingLists = $canListPackingLists;
$this->listsPackingLists = $listsPackingLists;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canListPackingLists->passes();
$query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($request->input('filters')));
return $this->collectionResponse(PackingListPendingInvoiceResource::collection($query));
}
}
@@ -0,0 +1,64 @@
<?php
namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\PackingLists\Standards\Rules\CanListPackingLists;
use App\Http\Resources\PackingListPendingPaymentResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ListPackingListsPendingPaymentLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => '(Pending Payment) Retrieved PackingLists',
'message' => 'You have successfully retrieved a list of PackingLists'
];
}
/** @var CanListPackingLists */
private $canListPackingLists;
/** @var ListsPackingLists */
private $listsPackingLists;
/**
* ListPackingListsPendingPaymentLogic constructor.
* @param CanListPackingLists $canListPackingLists
* @param ListsPackingLists $listsPackingLists
*/
public function __construct(CanListPackingLists $canListPackingLists, ListsPackingLists $listsPackingLists)
{
$this->canListPackingLists = $canListPackingLists;
$this->listsPackingLists = $listsPackingLists;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canListPackingLists->passes();
$query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($request->input('filters')));
foreach ($query->items() as $item) {
//from middleware
if($request->input('storages')){
$item['storages'] = $request->input('storages');
}
}
return $this->collectionResponse(PackingListPendingPaymentResource::collection($query));
}
}
@@ -54,7 +54,8 @@ class CreatePackageProcessor
$modificationValue = 1;
if($replica->owner->owner instanceof Order){
$modificationValue = in_array( $replica->owner->owner->companyModule->id, WarehouseReferences::REPLICA_WHITE_LIST) ? 0 : 1;
// $modificationValue = in_array( $replica->owner->owner->companyModule->id, WarehouseReferences::REPLICA_WHITE_LIST) ? 0 : 1;
$modificationValue = 1;
// if customer in segment 'No Extra Centimeter Charged'
$segmentId = Segment::where('name', 'No Extra Centimeter Charged')->first()->id;
@@ -73,4 +74,4 @@ class CreatePackageProcessor
}
}
}
@@ -3,6 +3,7 @@
namespace App\Classes\Modules\PackingLists\Processors\V2;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Anthropic\Services\CreatesClaudeResponse;
use App\Classes\Modules\Orders\Services\FetchesDataFromYDPortal;
use App\Classes\Modules\OpenAI\Services\CreatesChatGPTResponse;
use App\Models\PackingList;
@@ -19,14 +20,19 @@ class FetchByTrakingNoYdPortalV2Processor
/** @var CreatesChatGPTResponse */
private $createsChatGPTResponse;
/** @var CreatesClaudeResponse */
private $createsClaudeResponse;
/**
* @param FetchesDataFromYDPortal $fetchesDataFRomYDPortal
* @param CreatesChatGPTResponse $createsChatGPTResponse
* @param CreatesClaudeResponse $createsClaudeResponse
*/
public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal, CreatesChatGPTResponse $createsChatGPTResponse)
public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal, CreatesChatGPTResponse $createsChatGPTResponse, CreatesClaudeResponse $createsClaudeResponse)
{
$this->fetchesDataFRomYDPortal = $fetchesDataFRomYDPortal;
$this->createsChatGPTResponse = $createsChatGPTResponse;
$this->createsClaudeResponse = $createsClaudeResponse;
}
@@ -129,9 +135,9 @@ class FetchByTrakingNoYdPortalV2Processor
else{
$isUpdated = false;
if($item['tracking']){
$isTranslatedPreviouly = $this->checkIfTranslationAlreadyExist(!empty($item['tracking']) ? $item['tracking'] : "");
$result = $isTranslatedPreviouly;
if (!$isTranslatedPreviouly){
$isTranslatedPreviously = $this->checkIfTranslationAlreadyExist(!empty($item['tracking']) ? $item['tracking'] : "");
$result = $isTranslatedPreviously;
if (!$isTranslatedPreviously){
$result = $this->translateTracking($item['tracking']);
}
if ($result && $existingRecord->tracking_english !== $result) {
@@ -143,9 +149,9 @@ class FetchByTrakingNoYdPortalV2Processor
}
if($item['remark']) {
$isTranslatedPreviouly = $this->checkIfTranslationAlreadyExist(!empty($item['remark']) ? $item['remark'] : "");
$result = $isTranslatedPreviouly;
if (!$isTranslatedPreviouly){
$isTranslatedPreviously = $this->checkIfTranslationAlreadyExist(!empty($item['remark']) ? $item['remark'] : "");
$result = $isTranslatedPreviously;
if (!$isTranslatedPreviously){
$result = $this->translateTracking($item['remark']);
}
@@ -189,7 +195,7 @@ class FetchByTrakingNoYdPortalV2Processor
$trackingDate = Carbon::parse($trackingtime);
$trackingYear = $trackingDate->year;
if($remark && preg_match('/\b\d{1,2}[-\/.]\d{1,2}\b/', $remark) && $eta === null && $etd === null){
if($remark && $eta === null && $etd === null){
$existingRecord = YDOrderTracking::where('remark', $remark)->where(function ($query) {
$query->whereNotNull('eta')
->orWhereNotNull('etd');
@@ -203,14 +209,27 @@ class FetchByTrakingNoYdPortalV2Processor
];
}
$userPrompt = "Show me the answer in json string without escape, e.g. {'ETA': '', 'ETD': ''}. ".$remark." What is the ETA and ETD?";
$userPrompt = "You must respond with raw JSON only.
No explanations.
No markdown.
No code fences.
No comments.
Only this JSON structure:
{\"ETA\":\"\", \"ETD\":\"\"}
Dates must be strings in YYYY-MM-DD format.
{$remark}
What are the ETA and ETD?";
Log::info('prompt: '.$userPrompt);
$result = $this->createsChatGPTResponse->execute($userPrompt);
$result = $this->createsClaudeResponse->execute($userPrompt);
Log::info('result (json_encoded): '.json_encode($result));
$content = $result['choices'][0]['message']['content'] ?? null;
// $content = $result['choices'][0]['message']['content'] ?? null;
$content = $result['content'][0]['text'] ?? '[]';
Log::info('content (json_encoded):'. json_encode($content));
if ($content) {
$parsedContent = json_decode(str_replace("'", '"', $content), true);
$parsedContent = json_decode($content, true);
// $parsedContent = json_decode(str_replace("'", '"', $content), true);
if (is_array($parsedContent) && isset($parsedContent['ETA'], $parsedContent['ETD'])) {
Log::info('parsedContent ETA:'. $parsedContent['ETA']);
Log::info('parsedContent ETD:'. $parsedContent['ETD']);
@@ -310,9 +329,10 @@ class FetchByTrakingNoYdPortalV2Processor
{
$userPrompt = "Please translate mandarin to english and return result in this format, e.g. {'mandarin': '.$textToTranslate.', 'english': ''}. ".$textToTranslate." ";
Log::info('prompt: '.$userPrompt);
$result = $this->createsChatGPTResponse->execute($userPrompt);
$result = $this->createsClaudeResponse->execute($userPrompt);
Log::info('result (json_encoded): '.json_encode($result));
$content = $result['choices'][0]['message']['content'] ?? null;
// $content = $result['choices'][0]['message']['content'] ?? null;
$content = $result['content'][0]['text'] ?? '[]';
Log::info('content (json_encoded):'. json_encode($content));
$parsedContent = json_decode(str_replace("'", '"', $content), true);
@@ -0,0 +1,70 @@
<?php
namespace App\Classes\Modules\Rules\ControllersLogic;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Rules\DataTransferObjects\CheckEInvoiceRuleDTO;
use App\Classes\Modules\Rules\Services\RuleEvaluator;
use App\Classes\Modules\Rules\Standards\Rules\CanPassEInvoicePromptedRule;
use App\Classes\Modules\Rules\Standards\Rules\CanPassTINRule;
use App\Http\Resources\RuleResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CheckEInvoiceRuleLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Rule Check E-Invoice',
'message' => 'You have successfully passed all rules evaluated'
];
}
/** @var RuleEvaluator */
private $ruleEvaluator;
/** @var CanPassEInvoicePromptedRule */
private $canPassEInvoicePromptedRule;
/** @var CanPassTINRule */
private $canPassTINRule;
/**
* CheckEInvoiceRuleLogic constructor.
*/
public function __construct(RuleEvaluator $ruleEvaluator, CanPassEInvoicePromptedRule $canPassEInvoicePromptedRule, CanPassTINRule $canPassTINRule)
{
$this->ruleEvaluator = $ruleEvaluator;
$this->canPassEInvoicePromptedRule = $canPassEInvoicePromptedRule;
$this->canPassTINRule = $canPassTINRule;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
* @throws \App\Classes\Exceptions\CriteriaNotFulfilledException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new CheckEInvoiceRuleDTO($request->all());
$result = $this->ruleEvaluator->evaluate([
$this->canPassEInvoicePromptedRule,
$this->canPassTINRule,
], $dto);
if ($result->failed()) {
throw new CriteriaNotFulfilledException("- " . implode("<br>- ", $result->messages()));
}
return $this->resourceResponse(new RuleResource((object)$result));
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\Modules\Rules\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class CheckEInvoiceRuleDTO implements DataTransferObject
{
public int $companyModuleId;
public function __construct(array $data)
{
$this->companyModuleId = $data['company_module_id'];
}
public function toArray(): array
{
return [
'company_module_id' => $this->companyModuleId,
];
}
}
@@ -0,0 +1,44 @@
<?php
namespace App\Classes\Modules\Rules\Services;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\General\Interfaces\DataTransferObject;
use App\Classes\Exceptions\AccessForbiddenException;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\Exceptions\RequestValidationException;
use App\Classes\ValueObjects\Response\RuleEvaluationResult;
class RuleEvaluator //For using AbstractRule
{
/**
* Evaluate multiple rules.
*
* @param AbstractRule[] $rules
* @param DataTransferObject|null $object
* @return RuleEvaluationResult
*/
public function evaluate(array $rules, ?DataTransferObject $object = null): RuleEvaluationResult
{
$messages = [];
$success = true;
foreach ($rules as $rule) {
try {
if (!$rule->passes($object)) {
$success = false;
$messages[] = get_class($rule) . ' failed without exception';
}
} catch (AccessForbiddenException | RequestValidationException | CriteriaNotFulfilledException $e) {
$success = false;
$messages[] = $e->getMessage();
} catch (\Exception $e) {
$success = false;
$messages[] = 'Unexpected error in ' . get_class($rule) . ': ' . $e->getMessage();
}
}
return new RuleEvaluationResult($success, $messages);
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\Rules\Standards\Rules;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use Illuminate\Support\Facades\Log;
class CanPassEInvoicePromptedRule extends AbstractRule
{
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/**
* CanPassEInvoicePromptedRule constructor.
* @param FetchesCompanyModule $fetchesCompanyModule
*/
public function __construct(FetchesCompanyModule $fetchesCompanyModule)
{
$this->fetchesCompanyModule = $fetchesCompanyModule;
}
/**
* @return bool
*/
protected function authorized($object): bool
{
return true;
}
/**
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @return bool
*/
protected function criteria($object): bool
{
//Check if account requires E-Invoice
$companyModule = $this->fetchesCompanyModule->execute(['id' => $object->companyModuleId]);
if($companyModule->company->e_invoice === null){
throw new CriteriaNotFulfilledException("Please refresh page to answer question related to E-Invoice.");
}
return true;
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Classes\Modules\Rules\Standards\Rules;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
class CanPassTINRule extends AbstractRule
{
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/**
* CanPassTINRule constructor.
* @param FetchesCompanyModule $fetchesCompanyModule
*/
public function __construct(FetchesCompanyModule $fetchesCompanyModule)
{
$this->fetchesCompanyModule = $fetchesCompanyModule;
}
/**
* @return bool
*/
protected function authorized($object): bool
{
return true;
}
/**
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @return bool
*/
protected function criteria($object): bool
{
//Check if TIN already provided if account requires E-Invoice
$companyModule = $this->fetchesCompanyModule->execute(['id' => $object->companyModuleId]);
if($companyModule->company->e_invoice === 1 && !$companyModule->company->tin){
throw new CriteriaNotFulfilledException("Please provide all requested E-Invoice Info.");
}
return true;
}
}
@@ -5,6 +5,7 @@ namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Jobs\Commands\V2\ReleaseGoodsToCustomerV2CommandJob;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
@@ -23,7 +24,7 @@ use App\Http\Resources\WalletTransactionResource;
use App\Models\Wallet;
use App\Classes\Modules\Transactions\Processors\ReleaseGoodsToCustomerProcessor;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use Illuminate\Support\Facades\Log;
class CreateGroupsLogic extends AbstractControllerLogic
{
@@ -226,8 +227,11 @@ class CreateGroupsLogic extends AbstractControllerLogic
$paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, $reqBankCode, false);
if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
$pL = $invoice->owner;
$this->releaseGoodsToCustomerProcessor->execute($pL, $invoice);
// $pL = $invoice->owner;
// $this->releaseGoodsToCustomerProcessor->execute($pL, $invoice);
$obj = json_encode($invoice);
Log::info("Preparing to release goods for invoice: {$obj}");
ReleaseGoodsToCustomerV2CommandJob::dispatch($invoice);
}
}
@@ -7,8 +7,12 @@ use App\Classes\Modules\Transactions\Services\FetchesGroup;
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use App\Classes\Modules\Transactions\Services\DeletesGroup;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Transaction;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class DeleteGroupLogic extends AbstractControllerLogic
{
@@ -48,7 +52,7 @@ class DeleteGroupLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
ini_set('memory_limit', '-1');
ini_set('memory_limit', '-1');
$group = $this->fetchesGroup->execute(['id' => $request->route('id')]);
@@ -59,7 +63,12 @@ class DeleteGroupLogic extends AbstractControllerLogic
$this->deletesGroup->execute($group);
$topUpTransaction = Transaction::where('payment_reference', $group->reference)->first();
if($topUpTransaction && $topUpTransaction->type === TransactionType::TOP_UP && $topUpTransaction->status !== ApprovalStatus::APPROVED && $topUpTransaction->status !== ApprovalStatus::COMPLETED){
$topUpTransaction->delete();
}
return $this->response([]);
}
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\FetchesGroup;
use App\Classes\Modules\Transactions\Standards\Rules\CanFetchTransaction;
use App\Http\Resources\GroupPaidInvoicePNBPageResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchGroupLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Fetched Group',
'message' => 'You have successfully retrieved a Group'
];
}
/** @var CanFetchTransaction */
private $canFetchTransaction;
/** @var FetchesGroup */
private $fetchesGroup;
/**
* FetchGroupLogic constructor.
* @param CanFetchTransaction $canFetchTransaction
* @param FetchesGroup $fetchesGroup
*/
public function __construct(CanFetchTransaction $canFetchTransaction, FetchesGroup $fetchesGroup)
{
$this->canFetchTransaction = $canFetchTransaction;
$this->fetchesGroup = $fetchesGroup;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchTransaction->passes();
$query = $this->fetchesGroup->execute(['id' => $request->route('group_id')]);
return $this->resourceResponse(new GroupPaidInvoicePNBPageResource($query));
}
}
@@ -0,0 +1,61 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Standards\Rules\CanFetchTransaction;
use App\Http\Resources\TransactionWithStorageResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchTransactionLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Fetched Transaction',
'message' => 'You have successfully retrieved a Transaction'
];
}
/** @var CanFetchTransaction */
private $canFetchTransaction;
/** @var FetchesTransaction */
private $fetchesTransaction;
/**
* FetchTransactionLogic constructor.
* @param CanFetchTransaction $canFetchTransaction
* @param FetchesTransaction $fetchesTransaction
*/
public function __construct(CanFetchTransaction $canFetchTransaction, FetchesTransaction $fetchesTransaction)
{
$this->canFetchTransaction = $canFetchTransaction;
$this->fetchesTransaction = $fetchesTransaction;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchTransaction->passes();
$query = $this->fetchesTransaction->execute(['id' => $request->route('transaction_id')]);
if($request->input('storages')){
$query->storages = $request->input('storages'); //from middleware
}
return $this->resourceResponse(new TransactionWithStorageResource($query));
}
}
@@ -4,9 +4,11 @@ namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\ListsGroups;
use App\Http\Resources\GroupPaidInvoicesPNBPageResource;
use App\Http\Resources\GroupResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ListGroupsLogic extends AbstractControllerLogic
{
@@ -34,9 +36,17 @@ class ListGroupsLogic extends AbstractControllerLogic
public function logic(Request $request) : JsonResponse
{
$filtersJson = $request->input('filters');
$filters = is_string($filtersJson) ? json_decode($filtersJson, true) : $filtersJson;
$section = $filters['section'] ?? null;
$query = $this->listsGroups->execute($this->listsGroups->deserializeFilters($request->input('filters')));
return $this->collectionResponse(GroupResource::collection($query));
if($section === 'customerPaidGroupInvoiceComponent'){
return $this->collectionResponse(GroupPaidInvoicesPNBPageResource::collection($query));
}
else{
return $this->collectionResponse(GroupResource::collection($query));
}
}
}
@@ -6,7 +6,6 @@ namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\ListsTransactions;
use App\Http\Resources\TransactionWithStorageResource;
use App\Http\Resources\TransactionResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
@@ -36,11 +35,14 @@ class ListTransactionsLogic extends AbstractControllerLogic
/** @var ListsTransactions */
private $listsTransactions;
public function logic(Request $request) : JsonResponse
{
$query = $this->listsTransactions->execute($this->listsTransactions->deserializeFilters($request->input('filters')));
foreach ($query->items() as $item) {
if($item instanceof \App\Models\Transaction && $item->owner->owner->companyModule){
$item['is_einvoice_applicable'] = $item->owner->owner->companyModule->company->e_invoice === 1;
}
}
if($request->input('storages')){
foreach ($query->items() as $item) {
@@ -50,11 +52,7 @@ class ListTransactionsLogic extends AbstractControllerLogic
});
$item['storages'] = $filteredStorages;
}
//return $this->collectionResponse(TransactionWithStorageResource::collection($query));
}
// else{
// return $this->collectionResponse(TransactionResource::collection($query));
//
return $this->collectionResponse(TransactionWithStorageResource::collection($query));
}
}
@@ -4,18 +4,12 @@
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Order;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Models\Document;
use Carbon\Carbon;
use App\Classes\Modules\Transactions\Processors\CreateShippingInvoiceTransactionDocProcessor;
class RegenerateShippingInvoiceTransactionLogic extends AbstractControllerLogic
{
@@ -29,23 +23,20 @@ class RegenerateShippingInvoiceTransactionLogic extends AbstractControllerLogic
];
}
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/** @var CreateShippingInvoiceTransactionDocProcessor */
private $createShippingInvoiceTransactionDocProcessor;
/**
* @param CreatesDocument $createsDocument
* @param CreateShippingInvoiceTransactionDocProcessor $createShippingInvoiceTransactionDocProcessor
*/
public function __construct(CreatesDocument $createsDocument, CreatesFiles $createsFiles)
public function __construct(CreateShippingInvoiceTransactionDocProcessor $createShippingInvoiceTransactionDocProcessor)
{
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
$this->createShippingInvoiceTransactionDocProcessor = $createShippingInvoiceTransactionDocProcessor;
}
public function logic(Request $request) : JsonResponse
{
return $this->response([]); //The business logic to generate normal invoice and e-invoice no longer so straight forward
$orders = Order::where('company_module_id', $request->route('company_module_id'))->get();
@@ -53,28 +44,10 @@ class RegenerateShippingInvoiceTransactionLogic extends AbstractControllerLogic
$invoices = $order->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->get();
foreach ($invoices as $invoice){
$invoice->documents()->delete();
// $invoice->documents()->delete();
$invoice->documents()->where('document_type', DocumentType::SHIPPING_EINVOICE)->delete();
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
$document =$this->createsDocument->execute($invoice, $document_object);
$this->createsFiles->execute($document, $document_object);
$this->createShippingInvoiceTransactionDocProcessor->execute($invoice);
// dump($document);
}
@@ -82,5 +55,4 @@ class RegenerateShippingInvoiceTransactionLogic extends AbstractControllerLogic
return $this->response([]);
}
}
@@ -0,0 +1,53 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Processors\CreateSalesOrderDocProcessor;
use App\Classes\ValueObjects\Constants\DocumentType;
class RegenerateSingleSalesOrderLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Regenerate Sales Order',
'message' => 'You have successfully regenerated sales order'
];
}
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var CreateSalesOrderDocProcessor */
private $createSalesOrderDocProcessor;
/**
* @param FetchesTransaction $fetchesTransaction
* @param CreateSalesOrderDocProcessor $createSalesOrderDocProcessor
*/
public function __construct(FetchesTransaction $fetchesTransaction, CreateSalesOrderDocProcessor $createSalesOrderDocProcessor)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->createSalesOrderDocProcessor = $createSalesOrderDocProcessor;
}
public function logic(Request $request) : JsonResponse
{
$invoice = $this->fetchesTransaction->execute(['id' => $request->route('invoice_id')]);
$invoice->documents()->where('document_type', DocumentType::SALES_ORDER)->delete();
$this->createSalesOrderDocProcessor->execute($invoice);
return $this->response([]);
}
}
@@ -0,0 +1,53 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Processors\CreateShippingEInvoiceDocProcessor;
use App\Classes\ValueObjects\Constants\DocumentType;
class RegenerateSingleShippingEInvoiceLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Regenerate Shipping E-Invoice',
'message' => 'You have successfully regenerated shipping e-invoice'
];
}
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var CreateShippingEInvoiceDocProcessor */
private $createShippingEInvoiceDocProcessor;
/**
* @param FetchesTransaction $fetchesTransaction
* @param CreateShippingEInvoiceDocProcessor $createShippingEInvoiceDocProcessor
*/
public function __construct(FetchesTransaction $fetchesTransaction, CreateShippingEInvoiceDocProcessor $createShippingEInvoiceDocProcessor)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->createShippingEInvoiceDocProcessor = $createShippingEInvoiceDocProcessor;
}
public function logic(Request $request) : JsonResponse
{
$invoice = $this->fetchesTransaction->execute(['id' => $request->route('invoice_id')]);
$invoice->documents()->where('document_type', DocumentType::SHIPPING_EINVOICE)->delete();
$this->createShippingEInvoiceDocProcessor->execute($invoice);
return $this->response([]);
}
}
@@ -4,19 +4,11 @@
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Order;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Models\Document;
use Carbon\Carbon;
use App\Classes\Modules\Transactions\Processors\CreateShippingInvoiceTransactionDocProcessor;
class RegenerateSingleShippingInvoiceTransactionLogic extends AbstractControllerLogic
{
@@ -30,51 +22,30 @@ class RegenerateSingleShippingInvoiceTransactionLogic extends AbstractController
];
}
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var CreateShippingInvoiceTransactionDocProcessor */
private $createShippingInvoiceTransactionDocProcessor;
/**
* @param CreatesDocument $createsDocument
* @param FetchesTransaction $fetchesTransaction
* @param CreateShippingInvoiceTransactionDocProcessor $createShippingInvoiceTransactionDocProcessor
*/
public function __construct(CreatesDocument $createsDocument, CreatesFiles $createsFiles, FetchesTransaction $fetchesTransaction)
public function __construct(FetchesTransaction $fetchesTransaction, CreateShippingInvoiceTransactionDocProcessor $createShippingInvoiceTransactionDocProcessor)
{
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
$this->fetchesTransaction = $fetchesTransaction;
$this->createShippingInvoiceTransactionDocProcessor = $createShippingInvoiceTransactionDocProcessor;
}
public function logic(Request $request) : JsonResponse
{
$invoice = $this->fetchesTransaction->execute(['id' => $request->route('invoice_id')]);
$invoice->documents()->delete();
// $invoice->documents()->delete();
$invoice->documents()->where('document_type', DocumentType::SHIPPING_INVOICE)->delete();
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
$document =$this->createsDocument->execute($invoice, $document_object);
$this->createsFiles->execute($document, $document_object);
$this->createShippingInvoiceTransactionDocProcessor->execute($invoice);
// dump($document);
@@ -0,0 +1,53 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Processors\CreateStorageEInvoiceDocProcessor;
use App\Classes\ValueObjects\Constants\DocumentType;
class RegenerateSingleStorageEInvoiceLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Regenerate Storage E-Invoice',
'message' => 'You have successfully regenerated storage e-invoice'
];
}
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var CreateStorageEInvoiceDocProcessor */
private $createStorageEInvoiceDocProcessor;
/**
* @param FetchesTransaction $fetchesTransaction
* @param CreateStorageEInvoiceDocProcessor $createStorageEInvoiceDocProcessor
*/
public function __construct(FetchesTransaction $fetchesTransaction, CreateStorageEInvoiceDocProcessor $createStorageEInvoiceDocProcessor)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->createStorageEInvoiceDocProcessor = $createStorageEInvoiceDocProcessor;
}
public function logic(Request $request) : JsonResponse
{
$invoice = $this->fetchesTransaction->execute(['id' => $request->route('invoice_id')]);
$invoice->documents()->where('document_type', DocumentType::STORAGE_EINVOICE)->delete();
$this->createStorageEInvoiceDocProcessor->execute($invoice);
return $this->response([]);
}
}
@@ -8,9 +8,10 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Processors\CreateStorageInvoiceDocTransactionFixProcessor;
use App\Classes\Modules\Transactions\Processors\CreateStorageInvoiceTransactionDocProcessor;
use App\Classes\Modules\Transactions\Standards\Rules\CanRegenerateStorageInvoice;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\DocumentType;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
@@ -30,19 +31,21 @@ class RegenerateSingleStorageInvoiceTransactionLogic extends AbstractControllerL
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var CreateStorageInvoiceDocTransactionFixProcessor */
private $createStorageInvoiceDocTransactionProcessor;
/** @var CreateStorageInvoiceTransactionDocProcessor */
private $createStorageInvoiceTransactionDocProcessor;
/** @var CanRegenerateStorageInvoice */
private $canRegenerateStorageInvoice;
/**
* @param CreatesDocument $createsDocument
* @param FetchesTransaction $fetchesTransaction
* @param CreateStorageInvoiceTransactionDocProcessor $createStorageInvoiceTransactionDocProcessor
* @param CanRegenerateStorageInvoice $canRegenerateStorageInvoice
*/
public function __construct(FetchesTransaction $fetchesTransaction, CreateStorageInvoiceDocTransactionFixProcessor $createStorageInvoiceDocTransactionProcessor, CanRegenerateStorageInvoice $canRegenerateStorageInvoice)
public function __construct(FetchesTransaction $fetchesTransaction, CreateStorageInvoiceTransactionDocProcessor $createStorageInvoiceTransactionDocProcessor, CanRegenerateStorageInvoice $canRegenerateStorageInvoice)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->createStorageInvoiceDocTransactionProcessor = $createStorageInvoiceDocTransactionProcessor;
$this->createStorageInvoiceTransactionDocProcessor = $createStorageInvoiceTransactionDocProcessor;
$this->canRegenerateStorageInvoice = $canRegenerateStorageInvoice;
}
@@ -51,17 +54,13 @@ class RegenerateSingleStorageInvoiceTransactionLogic extends AbstractControllerL
$this->canRegenerateStorageInvoice->passes();
$invoice = $this->fetchesTransaction->execute(['id' => $request->route('invoice_id')]);
$packingList = $invoice->owner;
$order = $packingList->owner;
$invoices = $order->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->get();
$invoice->documents()->where('document_type', DocumentType::STORAGE_INVOICE)->delete();
foreach ($invoices as $invoice){
if($invoice->id === (int) $request->route('invoice_id')){
$invoice->documents()->delete();
}
}
/** @var Transaction $invoice_transaction */
// $invoice_transaction = $packingList->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->whereIn('status', [ApprovalStatus::COMPLETED])->first();
$this->createStorageInvoiceTransactionDocProcessor->execute($invoice);
$this->createStorageInvoiceDocTransactionProcessor->execute($packingList, true);
Log::info(Auth::user()->email." regenerate storage invoice for transaction with id ".$request->route('invoice_id'));
return $this->response([]);
@@ -8,18 +8,15 @@ use App\Classes\Notifications\InvoiceIssuedEmail;
use App\Models\Document;
use App\Models\PackingList;
use App\Models\Transaction;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Jobs\CreatePerfexCRMInvoice;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use App\Classes\Modules\Transactions\Processors\CreateShippingInvoiceTransactionDocProcessor;
use App\Classes\Modules\Transactions\Processors\CreateShippingEInvoiceDocProcessor;
use App\Classes\Modules\Transactions\Processors\CreateSalesOrderDocProcessor;
use App\Models\Order;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class ApproveShippingInvoiceTransactionProcessor
{
@@ -27,27 +24,32 @@ class ApproveShippingInvoiceTransactionProcessor
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/** @var CheckStorageInvoiceTransactionProcessor */
private $storageInvoiceTransactionProcessor;
/** @var CreateShippingInvoiceTransactionDocProcessor */
private $createShippingInvoiceTransactionDocProcessor;
/** @var CreateSalesOrderDocProcessor */
private $createSalesOrderDocProcessor;
/** @var CreateShippingEInvoiceDocProcessor */
private $createShippingEInvoiceDocProcessor;
/**
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
* @param CheckStorageInvoiceTransactionProcessor $storageInvoiceTransactionProcessor
* @param CreateShippingInvoiceTransactionDocProcessor $createShippingInvoiceTransactionDocProcessor
* @param CreateSalesOrderDocProcessor $createSalesOrderDocProcessor
* @param CreateShippingEInvoiceDocProcessor $createShippingEInvoiceDocProcessor
*/
public function __construct(UpdatesTransactionStatus $updatesTransactionStatus, CreatesDocument $createsDocument, CreatesFiles $createsFiles, CheckStorageInvoiceTransactionProcessor $storageInvoiceTransactionProcessor)
public function __construct(UpdatesTransactionStatus $updatesTransactionStatus, CheckStorageInvoiceTransactionProcessor $storageInvoiceTransactionProcessor, CreateShippingInvoiceTransactionDocProcessor $createShippingInvoiceTransactionDocProcessor, CreateSalesOrderDocProcessor $createSalesOrderDocProcessor, CreateShippingEInvoiceDocProcessor $createShippingEInvoiceDocProcessor)
{
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
$this->storageInvoiceTransactionProcessor = $storageInvoiceTransactionProcessor;
$this->createShippingInvoiceTransactionDocProcessor = $createShippingInvoiceTransactionDocProcessor;
$this->createSalesOrderDocProcessor = $createSalesOrderDocProcessor;
$this->createShippingEInvoiceDocProcessor = $createShippingEInvoiceDocProcessor;
}
@@ -60,40 +62,32 @@ class ApproveShippingInvoiceTransactionProcessor
/** @var Transaction $invoice_transaction */
$invoice_transaction = $packingList->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::PENDING_SUBMISSION])->first();
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice_transaction->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice_transaction->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$companyModule = $invoice_transaction->owner->owner->companyModule;
Log::info('company module einvoice: ' . json_encode($companyModule->company->e_invoice));
if($companyModule->company->e_invoice)
{
// $this->createShippingEInvoiceDocProcessor->execute($invoice_transaction);
}
else{
$this->createShippingInvoiceTransactionDocProcessor->execute($invoice_transaction);
}
$this->createSalesOrderDocProcessor->execute($invoice_transaction);
$this->updatesTransactionStatus->execute($invoice_transaction, ApprovalStatus::APPROVED);
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice_transaction]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
/** @var Document $document */
$document = $this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
$user = $packingList->owner->companyModule->employees()->first();
if(app()->environment(['production'])) {
if(app()->environment(['production']) && $companyModule->company->e_invoice === 0) { //invoice issued email is only send to customer who has not opted in E-Invoice
$companyModule = $packingList->owner->companyModule;
$user = $companyModule->employees()->first();
$user->notify(new InvoiceIssuedEmail($user, $packingList));
}
$order = $packingList->owner()->first();
if($order instanceof Order){
$this->storageInvoiceTransactionProcessor->executeOrder($order);
// $this->storageInvoiceTransactionProcessor->executeOrder($order);
$is_credit_term = $order->companyModule->inviters()->withPivot('is_credit_term')->first()->pivot->is_credit_term;
$this->storageInvoiceTransactionProcessor->processByPackingList($packingList, $order, $is_credit_term);
}
return;
}
}
@@ -17,8 +17,6 @@ use App\Classes\Modules\Transactions\Services\DeletesGroup;
use App\Classes\Modules\Billplzs\Services\DeletesBillplzBill;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionDetailObject;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
@@ -30,6 +28,7 @@ use App\Http\Resources\TransactionWithStorageResource;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\Transaction;
use App\Models\YDOrderTracking;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
@@ -68,6 +67,8 @@ class CheckStorageInvoiceTransactionProcessor
private $defaultPricePerCBM = 3;
private $defaultNumberOfDaysFree = 5;
/**
* @param FetchesOrder $fetchesOrder
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
@@ -153,24 +154,30 @@ class CheckStorageInvoiceTransactionProcessor
return $results;
}
public function processByPackingList(PackingList $packingList, Order $order, bool $is_credit_term){
$this->getResults($packingList, $order, $is_credit_term);
}
private function getResults($packingList, $order, $is_credit_term){
$results = [];
$arrivalDateAtChinaWarehouse = $this->getArrivalDateAtChinaWarehoue($packingList);
$arrivalDateAtChinaWarehouse = $this->getArrivalDateAtChinaWarehouse($packingList);
LogHelper::channel('storage_invoices')->info('arrivalDateAtChinaWarehouse: '.json_encode($arrivalDateAtChinaWarehouse));
LogHelper::channel('storage_invoices')->info('destinationWarehousePackage: '.json_encode($packingList));
$eta = $this->getEtaFromPackingList($packingList);
if($arrivalDateAtChinaWarehouse && $eta){
$dataTimeToCheckNew = $this->getTrackingTimeEnteredDestinationPortWarehouse($packingList); //trackingTimeEnteredDestinationPortWarehouse
$dataTimeToCheckOld = $this->getEtaFromPackingList($packingList); //eta
if($arrivalDateAtChinaWarehouse && $dataTimeToCheckNew){
$transactions = $packingList->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->get();
// $transactions = $destinationWarehousePackage->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->where('transactions.status', ApprovalStatus::APPROVED)->get();
/** @var Transaction $invoice_transaction */
foreach ($transactions as $invoice_transaction){
LogHelper::channel('storage_invoices')->info('invoice_transaction bill_no: '. $invoice_transaction->bill_no);
$result = null;
if(!$is_credit_term){
$result = $this->processSingleTransactionOfTypeShippingInvoice($invoice_transaction, $packingList, $order->company_module_id, $eta);
$result = $this->processSingleTransactionOfTypeShippingInvoice($invoice_transaction, $packingList, $order->company_module_id, $dataTimeToCheckOld, $dataTimeToCheckNew);
}
else{
$result = $this->isPaidOrWaivedStorageInvoiceExist($invoice_transaction, $packingList, $eta);
else {
$result = $this->isPaidOrWaivedStorageInvoiceExist($invoice_transaction, $packingList, $dataTimeToCheckOld, $dataTimeToCheckNew);
}
if($result){
$results[] = $result;
@@ -180,8 +187,9 @@ class CheckStorageInvoiceTransactionProcessor
return $results;
}
private function getArrivalDateAtChinaWarehoue($packingList){
private function getArrivalDateAtChinaWarehouse($packingList){
if($packingList->type === PackingListType::SHIPPING_PACKING_LIST){
LogHelper::channel('storage_invoices')->info('packingList reference: '.json_encode($packingList->reference));
$receive_packing_list = PackingList::where('reference', $packingList->reference)->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST)->first();
LogHelper::channel('storage_invoices')->info('receive_packing_list: '.json_encode($receive_packing_list->transports));
$transport = $receive_packing_list->transports->first();
@@ -199,6 +207,17 @@ class CheckStorageInvoiceTransactionProcessor
return null;
}
private function getTrackingTimeEnteredDestinationPortWarehouse($packingList){
if ($packingList) {
$reference = $packingList->reference;
$trackingRow = YDOrderTracking::where('tracking_no', $reference)->where('tracking', '货物已进目的港仓库')->first();
if ($trackingRow) {
return Carbon::parse($trackingRow->tracking_time);
}
}
return null;
}
private function getEtaFromPackingList($packingList){
if ($packingList) {
$package = $packingList->packages->first();
@@ -219,21 +238,30 @@ class CheckStorageInvoiceTransactionProcessor
return null;
}
private function processSingleTransactionOfTypeShippingInvoice($transaction, $destinationWarehousePackage, $company_module_id, $eta){
private function processSingleTransactionOfTypeShippingInvoice($transaction, $destinationWarehousePackage, $company_module_id, $dataTimeToCheckOld, $dataTimeToCheckNew){
$resultNumberOfDaysFree = $this->defaultNumberOfDaysFree;
$pricePerCBM = $this->defaultPricePerCBM;
$resultNumberOfDaysFree = 10;
$dt1 = $eta->copy()->addDay()->startOfDay();
LogHelper::channel('storage_invoices')->info('trackingTime: '.json_encode($dataTimeToCheckNew));
$dt1 = $dataTimeToCheckNew->copy()->addDay()->startOfDay();
$dt2 = Carbon::now()->copy()->addDay()->startOfDay();
$interval = Carbon::parse($dt2)->diff($dt1);
LogHelper::channel('storage_invoices')->info('eta: '.json_encode($eta));
LogHelper::channel('storage_invoices')->info('dt1: '.json_encode($dt1));
LogHelper::channel('storage_invoices')->info('dt2: '.json_encode($dt2));
//Goods should arrive first before checking for number of days stored
if ($dt1->greaterThan($dt2)) {
return null;
}
LogHelper::channel('storage_invoices')->info('interval: '.json_encode($interval));
LogHelper::channel('storage_invoices')->info('Carbon now: '.json_encode(Carbon::now()));
$resultNumberOfDaysExceeded = $interval->days - $resultNumberOfDaysFree;
// to prevent negative number of days exceeded
if($resultNumberOfDaysExceeded < 0){
$resultNumberOfDaysExceeded = 0;
}
$storageInvoice = $destinationWarehousePackage->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->first();
$storageInvoiceId = 0;
$transactionDetailsItems = $transaction->transactionDetails()->get();
@@ -280,7 +308,15 @@ class CheckStorageInvoiceTransactionProcessor
if($paymentStorageTransaction){
$dateStorageInvoicePaid = $paymentStorageTransaction->created_at->copy()->addDay()->startOfDay();
LogHelper::channel('storage_invoices')->info('dateStorageInvoicePaid: '.$dateStorageInvoicePaid.', resultCurrentDate: '.$dt2->format('Y-m-d H:i:s'));
$intervalRecalculate = Carbon::parse($dateStorageInvoicePaid)->diff($dt1);
$dateTemp = $dt1->copy();
$newStorageInvoiceBusinessLogic = Carbon::parse('2025-09-09 00:00:00');
if ($dateStorageInvoicePaid->isBefore($newStorageInvoiceBusinessLogic)){
$dateTemp = $dataTimeToCheckOld->copy()->addDay()->startOfDay();
$resultNumberOfDaysFree = 10;
}
$intervalRecalculate = Carbon::parse($dateStorageInvoicePaid)->diff($dateTemp);
$resultNumberOfDaysExceeded = $intervalRecalculate->days - $resultNumberOfDaysFree;
$price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded;
@@ -350,15 +386,25 @@ class CheckStorageInvoiceTransactionProcessor
}
private function isPaidOrWaivedStorageInvoiceExist($transaction, $packingList, $eta){
private function isPaidOrWaivedStorageInvoiceExist($transaction, $packingList, $dataTimeToCheckOld, $dataTimeToCheckNew){
$resultNumberOfDaysFree = $this->defaultNumberOfDaysFree;
$pricePerCBM = $this->defaultPricePerCBM;
$resultNumberOfDaysFree = 10;
$dt1 = $eta->copy()->addDay()->startOfDay();
$resultStartDate = $dt1->format('Y-m-d');
$currentDatetime = Carbon::now();
$dt2 = $currentDatetime->copy()->addDay()->startOfDay();
$resultCurrentDate = $dt2->format('Y-m-d H:i:s');
$interval = Carbon::parse($dt2)->diff($dt1);
$dt2 = Carbon::now()->copy()->addDay()->startOfDay();
$newStorageInvoiceBusinessLogic = Carbon::parse('2025-09-09 00:00:00');
$transactoinCreatedAt = Carbon::parse($transaction->created_at);
if ($transactoinCreatedAt->isAfter($newStorageInvoiceBusinessLogic)) {
$pricePerCBM = $this->defaultPricePerCBM;
$dt1 = $dataTimeToCheckNew->copy()->addDay()->startOfDay();
$interval = Carbon::parse($dt2)->diff($dt1);
}
else{
$dt1 = $dataTimeToCheckOld->copy()->addDay()->startOfDay();
$interval = Carbon::parse($dt2)->diff($dt1);
$resultNumberOfDaysFree = 10;
}
$resultNumberOfDaysExceeded = $interval->days - $resultNumberOfDaysFree;
$paidStorageInvoice = $packingList->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->whereIn('transactions.status', [ApprovalStatus::COMPLETED])->first();
if($paidStorageInvoice){
@@ -402,8 +448,8 @@ class CheckStorageInvoiceTransactionProcessor
'storageInvoiceId' => $storageInvoiceId,
'numberOfDaysExceeded' => $resultNumberOfDaysExceeded,
'numberOfDaysFree' => $resultNumberOfDaysFree,
'startDate' => $resultStartDate,
'currentDate' => $resultCurrentDate,
'startDate' => $dt1->format('Y-m-d'),
'currentDate' => $dt2->format('Y-m-d H:i:s'),
'cbm' => $cbm,
'pricePerCBM' => $pricePerCBM,
'storageInvoice' => new TransactionWithStorageResource($storageInvoice)
@@ -0,0 +1,536 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\General\LogHelper;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\CreatesTransactionDetail;
use App\Classes\Modules\Transactions\Services\UpdatesTransaction;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionDetail;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Transactions\Services\DeletesGroup;
use App\Classes\Modules\Billplzs\Services\DeletesBillplzBill;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionDetailObject;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PackageType;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\TaxPercentage;
use App\Classes\ValueObjects\Constants\TransactionDetailType;
use App\Http\Resources\TransactionWithStorageResource;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class CheckStorageInvoiceTransactionV0Processor
{
/** @var FetchesOrder */
private $fetchesOrder;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var CreatesTransactionDetail */
private $createsTransactionDetail;
/** @var UpdatesTransaction */
private $updatesTransaction;
/** @var UpdatesTransactionDetail */
private $updatesTransactionDetail;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var DeletesGroup */
private $deletesGroup;
/** @var DeletesBillplzBill */
private $deletesBillplzBill;
private $defaultPricePerCBM = 3;
/**
* @param FetchesOrder $fetchesOrder
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param FetchesTransaction $fetchesTransaction
* @param CreatesTransaction $createsTransaction
* @param CreatesTransactionDetail $createsTransactionDetail
* @param UpdatesTransaction $updatesTransaction
* @param UpdatesTransactionDetail $updatesTransactionDetail
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param DeletesGroup $deletesGroup
* @param DeletesBillplzBill $deletesBillplzBill
*/
public function __construct(FetchesOrder $fetchesOrder, GeneratesTransactionBillNumber $generatesTransactionBillNumber, FetchesTransaction $fetchesTransaction, CreatesTransaction $createsTransaction, CreatesTransactionDetail $createsTransactionDetail, UpdatesTransaction $updatesTransaction, UpdatesTransactionDetail $updatesTransactionDetail, UpdatesTransactionStatus $updatesTransactionStatus, DeletesGroup $deletesGroup, DeletesBillplzBill $deletesBillplzBill)
{
$this->fetchesOrder = $fetchesOrder;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->fetchesTransaction = $fetchesTransaction;
$this->createsTransaction = $createsTransaction;
$this->createsTransactionDetail = $createsTransactionDetail;
$this->updatesTransaction = $updatesTransaction;
$this->updatesTransactionDetail = $updatesTransactionDetail;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->deletesGroup = $deletesGroup;
$this->deletesBillplzBill = $deletesBillplzBill;
if (env('APP_ENV') === 'production') {
// Production environment - 23rd September 2024
$targetDate = Carbon::create(2024, 9, 23, 0, 0, 0, 'Asia/Kuala_Lumpur');
} else {
// Non-production environment (development, local, etc.) - 22nd September 2024
$targetDate = Carbon::create(2024, 9, 22, 0, 0, 0, 'Asia/Kuala_Lumpur');
}
$nowMalaysia = Carbon::now('Asia/Kuala_Lumpur');
if ($nowMalaysia->greaterThanOrEqualTo($targetDate)) {
// LogHelper::channel('storage_invoices')->info('new defaultPricePerCBM RM6 true');
$this->defaultPricePerCBM = 6;
}
else{
// LogHelper::channel('storage_invoices')->info('new defaultPricePerCBM RM6 not yet');
}
}
/**
* @throws MalformedRequestException
*/
public function execute(int $orderReference)
{
$order = $this->fetchesOrder->execute(['reference' => $orderReference, 'with_packing_lists' => true]);
return $this->executeOrder($order);
}
public function executeOrder(Order $order){
$results = [];
$marking = $order->companyModule->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference;
$is_credit_term = $order->companyModule->inviters()->withPivot('is_credit_term')->first()->pivot->is_credit_term;
LogHelper::channel('storage_invoices')->info('orderId: '.$order->id.', orderReference: '.$order->reference.', marking: '.$marking.', is_credit_term: '.$is_credit_term);
$packingLists = $order->destinationWarehousePackages;
foreach ($packingLists as $packingList){
$newResults = $this->getResults($packingList, $order, $is_credit_term);
$results = array_merge($results, $newResults);
}
return $results;
}
public function executeShippingTransaction(Transaction $shippingInvoice){
LogHelper::channel('storage_invoices')->info('shippingInvoice: '.json_encode($shippingInvoice));
$results = [];
$pL = $shippingInvoice->owner;
$order = $pL->owner;
$is_credit_term = $order->companyModule->inviters()->withPivot('is_credit_term')->first()->pivot->is_credit_term;
$packingLists = $order->destinationWarehousePackages;
foreach ($packingLists as $packingList){
if($packingList->id === $pL->id){
$newResults = $this->getResults($packingList, $order, $is_credit_term);
$results = array_merge($results, $newResults);
}
}
return $results;
}
public function processByPackingList(PackingList $packingList, Order $order, bool $is_credit_term){
$this->getResults($packingList, $order, $is_credit_term);
}
private function getResults($packingList, $order, $is_credit_term){
$results = [];
$arrivalDateAtChinaWarehouse = $this->getArrivalDateAtChinaWarehouse($packingList);
LogHelper::channel('storage_invoices')->info('arrivalDateAtChinaWarehouse: '.json_encode($arrivalDateAtChinaWarehouse));
LogHelper::channel('storage_invoices')->info('destinationWarehousePackage: '.json_encode($packingList));
$eta = $this->getEtaFromPackingList($packingList);
if($arrivalDateAtChinaWarehouse && $eta){
$transactions = $packingList->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->get();
// $transactions = $destinationWarehousePackage->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->where('transactions.status', ApprovalStatus::APPROVED)->get();
/** @var Transaction $invoice_transaction */
foreach ($transactions as $invoice_transaction){
LogHelper::channel('storage_invoices')->info('invoice_transaction bill_no: '. $invoice_transaction->bill_no);
$result = null;
if(!$is_credit_term){
$result = $this->processSingleTransactionOfTypeShippingInvoice($invoice_transaction, $packingList, $order->company_module_id, $eta);
}
else{
$result = $this->isPaidOrWaivedStorageInvoiceExist($invoice_transaction, $packingList, $eta);
}
if($result){
$results[] = $result;
}
}
}
return $results;
}
private function getArrivalDateAtChinaWarehouse($packingList){
if($packingList->type === PackingListType::SHIPPING_PACKING_LIST){
LogHelper::channel('storage_invoices')->info('packingList reference: '.json_encode($packingList->reference));
$receive_packing_list = PackingList::where('reference', $packingList->reference)->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST)->first();
LogHelper::channel('storage_invoices')->info('receive_packing_list: '.json_encode($receive_packing_list->transports));
$transport = $receive_packing_list->transports->first();
if ($transport) {
$arrivalDateAtChinaWarehouse = Carbon::parse($transport->drop_date);
$dateToCompare = Carbon::parse(env('STORAGE_FEE_LAUNCH_DATE', '2023-12-11 00:00:00'));
// dd($dateToCompare);
if ($arrivalDateAtChinaWarehouse->isAfter($dateToCompare)) {
LogHelper::channel('storage_invoices')->info('transport: '.json_encode($transport));
LogHelper::channel('storage_invoices')->info('dateToCompare: '.$dateToCompare.', arrivalDateAtChinaWarehouse: '.$arrivalDateAtChinaWarehouse);
return $arrivalDateAtChinaWarehouse;
}
}
}
return null;
}
private function getEtaFromPackingList($packingList){
if ($packingList) {
$package = $packingList->packages->first();
if ($package) {
$container = $package->container()->first();
if ($container) {
$transport = $container->transports->first();
if ($transport) {
$schedule = $transport->schedules->last();
if ($schedule) {
LogHelper::channel('storage_invoices')->info('schedule: '.json_encode($schedule));
return $schedule->eta;
}
}
}
}
}
return null;
}
private function processSingleTransactionOfTypeShippingInvoice($transaction, $destinationWarehousePackage, $company_module_id, $eta){
$pricePerCBM = $this->defaultPricePerCBM;
$resultNumberOfDaysFree = 10;
$dt1 = $eta->copy()->addDay()->startOfDay();
$dt2 = Carbon::now()->copy()->addDay()->startOfDay();
$interval = Carbon::parse($dt2)->diff($dt1);
LogHelper::channel('storage_invoices')->info('eta: '.json_encode($eta));
LogHelper::channel('storage_invoices')->info('dt1: '.json_encode($dt1));
LogHelper::channel('storage_invoices')->info('dt2: '.json_encode($dt2));
//Goods should arrive first before checking for number of days stored
if ($dt1->greaterThan($dt2)) {
return null;
}
LogHelper::channel('storage_invoices')->info('interval: '.json_encode($interval));
LogHelper::channel('storage_invoices')->info('Carbon now: '.json_encode(Carbon::now()));
$resultNumberOfDaysExceeded = $interval->days - $resultNumberOfDaysFree;
// to prevent negative number of days exceeded
if($resultNumberOfDaysExceeded < 0){
$resultNumberOfDaysExceeded = 0;
}
$storageInvoice = $destinationWarehousePackage->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->first();
$storageInvoiceId = 0;
$transactionDetailsItems = $transaction->transactionDetails()->get();
$cbm = 0.00;
foreach ($transactionDetailsItems as $tdItem){
$quantity = $tdItem->quantity;
if($tdItem->price < 0.00){
$quantity = $quantity * -1;
}
$cbm = $cbm + $quantity;
}
$total_tax = 0;
$taxPercentage = TaxPercentage::DEFAULT;
$price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded;
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
LogHelper::channel('storage_invoices')->info('dateToCompare: '.json_encode($dateToCompare));
if(!$storageInvoice && $resultNumberOfDaysExceeded > 0 && $transaction->status != ApprovalStatus::COMPLETED){
LogHelper::channel('storage_invoices')->info('Created $transaction->id: '.$transaction->id);
$billNumber = $this->generatesTransactionBillNumber->execute('STOR-');
if (Carbon::now()->isAfter($dateToCompare)) {
$taxPercentage = TaxPercentage::SIX_PERCENT;
$total_tax = $price_cbm * $taxPercentage / 100;
$price_cbm = $price_cbm + $total_tax;
}
$storageInvoice = $this->createStorageInvoiceTransaction($destinationWarehousePackage, $billNumber, $company_module_id, $price_cbm, $total_tax);
$storageInvoiceId = $storageInvoice->id;
$this->createStorageInvoiceTransactionDetails($storageInvoice, $destinationWarehousePackage, $cbm, $pricePerCBM, $resultNumberOfDaysExceeded, $taxPercentage);
}
else if($storageInvoice){
$amount = $storageInvoice->amount;
//Additional handling for giving selected storage invoice a waiver
if(isset($storageInvoice->is_waived) && $storageInvoice->is_waived){
$pricePerCBM = 0;
$price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded;
}
//Additional handling for calculation of numberOfDaysExceeded in the event of the storage already paid
$paymentStorageTransaction = $storageInvoice->transactions()->where('transactions.type', TransactionType::PAYMENT)->where('transactions.status', ApprovalStatus::APPROVED)->first();
if($paymentStorageTransaction){
$dateStorageInvoicePaid = $paymentStorageTransaction->created_at->copy()->addDay()->startOfDay();
LogHelper::channel('storage_invoices')->info('dateStorageInvoicePaid: '.$dateStorageInvoicePaid.', resultCurrentDate: '.$dt2->format('Y-m-d H:i:s'));
$intervalRecalculate = Carbon::parse($dateStorageInvoicePaid)->diff($dt1);
$resultNumberOfDaysExceeded = $intervalRecalculate->days - $resultNumberOfDaysFree;
$price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded;
try{
$auditPricePerCbm = floor($amount / ($cbm * $resultNumberOfDaysExceeded));
LogHelper::channel('storage_invoices')->info('auditPricePerCbm: '.$auditPricePerCbm);
$pricePerCBM = $auditPricePerCbm;
}
catch(\Exception $ex){
LogHelper::channel('storage_invoices')->info('auditPricePerCbm: '.$ex);
}
}
if (Carbon::now()->isAfter($dateToCompare)) {
$taxPercentage = TaxPercentage::SIX_PERCENT;
$total_tax = $price_cbm * $taxPercentage / 100;
$price_cbm = $price_cbm + $total_tax;
}
$epsilon = 0.0001; // Tolerance for the comparison
LogHelper::channel('storage_invoices')->info('Update $transaction->id: '.$transaction->id);
LogHelper::channel('storage_invoices')->info('$storageInvoice->status: '.$storageInvoice->status);
LogHelper::channel('storage_invoices')->info('price_cbm: '.$price_cbm."-".gettype($price_cbm));
LogHelper::channel('storage_invoices')->info('amount: '.$amount);
$proceedToUpdate = false;
if(abs($price_cbm - $amount) > $epsilon && $storageInvoice->status !== ApprovalStatus::COMPLETED){
$paymentTransactions = $storageInvoice->transactions()->where('transactions.type', TransactionType::PAYMENT)->where('transactions.status', ApprovalStatus::PENDING_SUBMISSION)->get();
// if(!$isBackDoorCheck){
if(count($paymentTransactions) > 0){
$this->updatePaymentTransactionViaNonGroupPayment($paymentTransactions);
}
else{
$this->updatePaymentTransactionViaGroupPayment($storageInvoice);
}
//}
$proceedToUpdate = true;
}
if($proceedToUpdate || ($pricePerCBM == 0 && $amount != 0)){
LogHelper::channel('storage_invoices')->info('proceedToUpdate');
$storageInvoice = $this->updateStorageInvoiceTransaction($storageInvoice, $price_cbm, $total_tax);
$invoiceTransactionDetails = $storageInvoice->transactionDetails()->first();
$this->updateStorageInvoiceTransactionDetails($invoiceTransactionDetails, $destinationWarehousePackage, $cbm, $pricePerCBM, $resultNumberOfDaysExceeded, $taxPercentage);
}
$storageInvoiceId = $storageInvoice->id;
}
if($storageInvoiceId !== 0){
$result = [
'parentInvoiceId' => $transaction->id,
'storageInvoiceId' => $storageInvoiceId,
'numberOfDaysExceeded' => $resultNumberOfDaysExceeded,
'numberOfDaysFree' => $resultNumberOfDaysFree,
'startDate' => $dt1->format('Y-m-d'),
'currentDate' => $dt2->format('Y-m-d H:i:s'),
'cbm' => $cbm,
'pricePerCBM' => $pricePerCBM,
'storageInvoice' => new TransactionWithStorageResource($storageInvoice)
];
return $result;
}
}
private function isPaidOrWaivedStorageInvoiceExist($transaction, $packingList, $eta){
$pricePerCBM = $this->defaultPricePerCBM;
$resultNumberOfDaysFree = 10;
$dt1 = $eta->copy()->addDay()->startOfDay();
$resultStartDate = $dt1->format('Y-m-d');
$currentDatetime = Carbon::now();
$dt2 = $currentDatetime->copy()->addDay()->startOfDay();
$resultCurrentDate = $dt2->format('Y-m-d H:i:s');
$interval = Carbon::parse($dt2)->diff($dt1);
$resultNumberOfDaysExceeded = $interval->days - $resultNumberOfDaysFree;
$paidStorageInvoice = $packingList->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->whereIn('transactions.status', [ApprovalStatus::COMPLETED])->first();
if($paidStorageInvoice){
$storageInvoice = $paidStorageInvoice;
}
else{
$waivedStorageInvoice = $packingList->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->where('transactions.is_waived', 1)->whereIn('transactions.status', [ApprovalStatus::APPROVED])->first();
$storageInvoice = $waivedStorageInvoice;
}
if($storageInvoice){
$storageInvoiceId = $storageInvoice->id;
$transactionDetailsItems = $transaction->transactionDetails()->get();
$cbm = 0.00;
foreach ($transactionDetailsItems as $tdItem){
$quantity = $tdItem->quantity;
if($tdItem->price < 0.00){
$quantity = $quantity * -1;
}
$cbm = $cbm + $quantity;
}
if(isset($storageInvoice->is_waived) && $storageInvoice->is_waived){
$pricePerCBM = 0;
}
else{
try{
$auditPricePerCbm = floor($storageInvoice->amount / ($cbm * $resultNumberOfDaysExceeded));
LogHelper::channel('storage_invoices')->info('auditPricePerCbm: '.$auditPricePerCbm);
$pricePerCBM = $auditPricePerCbm;
}
catch(\Exception $ex){
LogHelper::channel('storage_invoices')->info('auditPricePerCbm: '.$ex);
}
}
if($storageInvoiceId !== 0){
$result = [
'parentInvoiceId' => $transaction->id,
'storageInvoiceId' => $storageInvoiceId,
'numberOfDaysExceeded' => $resultNumberOfDaysExceeded,
'numberOfDaysFree' => $resultNumberOfDaysFree,
'startDate' => $resultStartDate,
'currentDate' => $resultCurrentDate,
'cbm' => $cbm,
'pricePerCBM' => $pricePerCBM,
'storageInvoice' => new TransactionWithStorageResource($storageInvoice)
];
return $result;
}
}
return [];
}
private function updatePaymentTransactionViaGroupPayment($storageInvoice){
LogHelper::channel('storage_invoices')->info('updatePaymentTransactionViaGroupPayment');
$groups = $storageInvoice->groups()->whereNotIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::SUSPENDED])->get();
foreach ($groups as $grp){
$groupReference = $grp->reference;
$walletTransaction = $this->fetchesTransaction->execute(['payment_reference' => $groupReference]);
if($walletTransaction->status === ApprovalStatus::PENDING_SUBMISSION || $walletTransaction->status === ApprovalStatus::PENDING_VERIFICATION){
$grp->status = ApprovalStatus::EXPIRED;
$grp->save();
$this->deletesGroup->execute($grp);
$this->updatesTransactionStatus->execute($walletTransaction, ApprovalStatus::EXPIRED);
if($walletTransaction->payment_reference){
$deletedBillplzBill = $this->deletesBillplzBill->execute($walletTransaction->payment_reference);
LogHelper::channel('storage_invoices')->info('deletedBillplzBill TransactionType::WALLET: '.json_encode($deletedBillplzBill));
}
}
}
}
private function updatePaymentTransactionViaNonGroupPayment($paymentTransactions){
LogHelper::channel('storage_invoices')->info('updatePaymentTransactionViaNonGroupPayment');
foreach ($paymentTransactions as $paymentTransaction){
$this->updatesTransactionStatus->execute($paymentTransaction, ApprovalStatus::EXPIRED);
if($paymentTransaction->payment_reference){
$deletedBillplzBill = $this->deletesBillplzBill->execute($paymentTransaction->payment_reference);
LogHelper::channel('storage_invoices')->info('deletedBillplzBill TransactionType::WALLET: '.json_encode($deletedBillplzBill));
}
}
}
private function updateStorageInvoiceTransaction(Transaction $transaction, float $totalAmount, float $totalTax){
$object = new TransactionObject(
$transaction->bill_no,
TransactionType::STORAGE_INVOICE,
1,
$transaction->receiver,
1,
PaymentMethodType::CASH,
$totalAmount,
$totalAmount,
1,
1,
0,
$totalTax,
0,
null,
ApprovalStatus::APPROVED
);
/** @var Transaction $invoice_transaction */
$invoice_transaction = $this->updatesTransaction->execute($transaction, $object);
return $invoice_transaction;
}
private function updateStorageInvoiceTransactionDetails($invoice_transaction_details, PackingList $packing_list, $cbm, $pricePerCBM, $numberOfDays, $taxPercentage){
$object_detail = new TransactionDetailObject(
'STORAGE_FEE',
TransactionDetailType::STORAGE_FEE.' for '.$numberOfDays. ' days * RM'.$pricePerCBM.'<br>'.round($packing_list->packages->where('type', '!=', PackageType::OVER_WEIGHT)->sum('quantity'), 3).' CTNS - '.round($cbm, 3).' CBM',
$cbm,
$pricePerCBM * $numberOfDays,
$taxPercentage
);
$this->updatesTransactionDetail->execute($invoice_transaction_details, $object_detail);
}
private function createStorageInvoiceTransaction(PackingList $packing_list, string $billNumber, int $companyModuleId, float $totalAmount, float $totalTax){
$object = new TransactionObject(
$billNumber,
TransactionType::STORAGE_INVOICE,
1,
$companyModuleId,
1,
PaymentMethodType::CASH,
$totalAmount,
$totalAmount,
1,
1,
0,
$totalTax,
0,
null,
ApprovalStatus::APPROVED
);
/** @var Transaction $invoice_transaction */
$invoice_transaction = $this->createsTransaction->execute($packing_list, $object);
return $invoice_transaction;
}
private function createStorageInvoiceTransactionDetails($invoice_transaction, PackingList $packing_list, $cbm, $pricePerCBM, $numberOfDays, $taxPercentage){
$object_detail = new TransactionDetailObject(
'STORAGE_FEE',
TransactionDetailType::STORAGE_FEE.' for '.$numberOfDays. ' days * RM'.$pricePerCBM.'<br>'.round($packing_list->packages->where('type', '!=', PackageType::OVER_WEIGHT)->sum('quantity'), 3).' CTNS - '.round($cbm, 3).' CBM',
$cbm,
$pricePerCBM * $numberOfDays,
$taxPercentage
);
$this->createsTransactionDetail->execute($invoice_transaction, $object_detail);
}
}
@@ -105,7 +105,8 @@ class CreateInvoiceTransactionProcessor
$order = $packing_list->owner;
$companyModule = $order->companyModule;
$connection = $companyModule->connections()->first();
$address = $order->addresses()->first();
// $address = $order->addresses()->first();
$address = $order->addresses()->whereIn('status', [2])->first();
$base_price_constant = $this->fetchesSegmentConstant->execute(['segment_id' => 1, 'reference' => SegmentConstants::BASE_PRICE]);
$warehouse_rate_constant = $this->fetchesSegmentConstant->execute(['segment_id' => 1, 'reference' => SegmentConstants::WAREHOUSE_RATE]);
@@ -150,19 +151,32 @@ class CreateInvoiceTransactionProcessor
$containerPackingLists = collect();
$hasMinimumCharge = null;
foreach ($container->packingLists as $packingList){
if($packingList->owner instanceof CompanyModule) continue;
if($packingList->owner->companyModule->id !== $companyModule->id) continue;
$containerPackingLists->push($packingList);
foreach ($container->packingLists as $singlePL){
if($singlePL->owner instanceof CompanyModule) continue;
if($singlePL->owner->companyModule->id !== $companyModule->id) continue;
$containerPackingLists->push($singlePL);
if(!$hasMinimumCharge) {
$hasMinimumCharge = $packingList->transactions()->whereHas('transactionDetails', function ($query){
$hasMinimumCharge = $singlePL->transactions()->whereHas('transactionDetails', function ($query){
$query->where('reference', 'MIN_CBM_CHARGES');
})->first();
}
}
$sameOrderSameContainerPackingLists = $order->packingLists()
->where('type', PackingListType::SHIPPING_PACKING_LIST)
->whereHas('containers', function ($query) use ($container) {
$query->where('reference', $container->reference);
})
->get();
foreach ($sameOrderSameContainerPackingLists as $item) {
if (! $containerPackingLists->contains('id', $item['id'])) {
$containerPackingLists->push($item);
}
}
Log::info('AUDIT containerPackingLists: ' . json_encode($containerPackingLists));
$totalContainerCbm = $containerPackingLists->sum(function($packingList){
$billable_packing_list = $packingList->packingLists()->first();
$billable_packing_list = $billable_packing_list ? $billable_packing_list : $packingList;
@@ -0,0 +1,65 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Models\Document;
use App\Models\Transaction;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
class CreateSalesOrderDocProcessor
{
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/**
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
*/
public function __construct(CreatesDocument $createsDocument, CreatesFiles $createsFiles)
{
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
}
/**
* @throws MalformedRequestException
*/
public function execute(Transaction $invoice_transaction)
{
$view = 'pages.pdfs.sales_order';
$companyModule = $invoice_transaction->owner->owner->companyModule;
$user = $companyModule->employees()->first();
$brn = $companyModule->company->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first();
$documentDate = $invoice_transaction->created_at;
$documentIdentifierPrefix = 'S/O No: ';
$documentIdentifier = 'SO-'.$invoice_transaction->bill_no;
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice_transaction, 'brn' => $brn, 'document_date' => $documentDate, 'document_identifier' => $documentIdentifier, 'document_identifier_prefix' => $documentIdentifierPrefix]);
$document_object = new DocumentObject(
DocumentType::SALES_ORDER,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'sales_order'
);
/** @var Document $document */
$document =$this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
}
}
@@ -0,0 +1,95 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Models\Document;
use App\Models\Transaction;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\ValueObjects\Constants\KVPKey;
class CreateShippingEInvoiceDocProcessor
{
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/** @var CreatesKeyValuePair */
private $createsKeyValuePair;
/**
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
* @param CreatesKeyValuePair $createsKeyValuePair
*/
public function __construct(CreatesDocument $createsDocument, CreatesFiles $createsFiles, CreatesKeyValuePair $createsKeyValuePair)
{
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
$this->createsKeyValuePair = $createsKeyValuePair;
}
/**
* @throws MalformedRequestException
*/
public function execute(Transaction $invoice_transaction)
{
$view = 'pages.pdfs.shipping_einvoice';
$companyModule = $invoice_transaction->owner->owner->companyModule;
$user = $companyModule->employees()->first();
$brn = $companyModule->company->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first();
$lastDayOfMonth = $invoice_transaction->created_at->copy()->endOfMonth();
$documentDate = $lastDayOfMonth;
$documentIdentifierPrefix = 'EI#: ';
$autoCountInvoiceId = '';
$autoCountEInvoiceValidationLink = 'CIEF';
$metadata = $invoice_transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if($metadata){
$autoCountInvoiceId = $metadata->value;
}
$metadata = $invoice_transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK)->first();
if($metadata){
$autoCountEInvoiceValidationLink = $metadata->value;
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, [
'invoice_transaction' => $invoice_transaction,
'brn' => $brn,
'document_date' => $documentDate,
'document_identifier' => $autoCountInvoiceId,
'document_identifier_prefix' => $documentIdentifierPrefix,
'autocountEInvoiceValidationLink' => $autoCountEInvoiceValidationLink,
]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_EINVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_einvoice'
);
/** @var Document $document */
$document =$this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
$keyValuePairObject = new KeyValuePairObject(KVPKey::EINVOICE_ISSUED, 1);
$this->createsKeyValuePair->execute($invoice_transaction, $keyValuePairObject);
}
}
@@ -0,0 +1,75 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Models\Document;
use App\Models\Transaction;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use Carbon\Carbon;
class CreateShippingInvoiceTransactionDocProcessor
{
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/**
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
*/
public function __construct(CreatesDocument $createsDocument, CreatesFiles $createsFiles)
{
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
}
/**
* @throws MalformedRequestException
*/
public function execute(Transaction $invoice_transaction)
{
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice_transaction->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice_transaction->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00'));
if ($shippingInvoiceTransactionCreatedDate->isAfter($eInvoiceStartDate)) {
$view = 'pages.pdfs.shipping_invoice_sst_v2';
}
$companyModule = $invoice_transaction->owner->owner->companyModule;
$user = $companyModule->employees()->first();
$brn = $companyModule->company->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first();
$documentDate = $invoice_transaction->created_at;
$documentIdentifierPrefix = 'Invoice No: ';
$documentIdentifier = $invoice_transaction->bill_no;
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice_transaction, 'brn' => $brn, 'document_date' => $documentDate, 'document_identifier' => $documentIdentifier, 'document_identifier_prefix' => $documentIdentifierPrefix]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
/** @var Document $document */
$document =$this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
}
}
@@ -0,0 +1,95 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Models\Document;
use App\Models\Transaction;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\ValueObjects\Constants\KVPKey;
class CreateStorageEInvoiceDocProcessor
{
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/** @var CreatesKeyValuePair */
private $createsKeyValuePair;
/**
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
* @param CreatesKeyValuePair $createsKeyValuePair
*/
public function __construct(CreatesDocument $createsDocument, CreatesFiles $createsFiles, CreatesKeyValuePair $createsKeyValuePair)
{
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
$this->createsKeyValuePair = $createsKeyValuePair;
}
/**
* @throws MalformedRequestException
*/
public function execute(Transaction $invoice_transaction)
{
$view = 'pages.pdfs.shipping_einvoice';
$companyModule = $invoice_transaction->owner->owner->companyModule;
$user = $companyModule->employees()->first();
$brn = $companyModule->company->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first();
$lastDayOfMonth = $invoice_transaction->created_at->copy()->endOfMonth();
$documentDate = $lastDayOfMonth;
$documentIdentifierPrefix = 'EI#: ';
$autoCountInvoiceId = '';
$autoCountEInvoiceValidationLink = 'CIEF';
$metadata = $invoice_transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if($metadata){
$autoCountInvoiceId = $metadata->value;
}
$metadata = $invoice_transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK)->first();
if($metadata){
$autoCountEInvoiceValidationLink = $metadata->value;
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, [
'invoice_transaction' => $invoice_transaction,
'brn' => $brn,
'document_date' => $documentDate,
'document_identifier' => $autoCountInvoiceId,
'document_identifier_prefix' => $documentIdentifierPrefix,
'autocountEInvoiceValidationLink' => $autoCountEInvoiceValidationLink,
]);
$document_object = new DocumentObject(
DocumentType::STORAGE_EINVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_einvoice'
);
/** @var Document $document */
$document =$this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
$keyValuePairObject = new KeyValuePairObject(KVPKey::EINVOICE_ISSUED, 1);
$this->createsKeyValuePair->execute($invoice_transaction, $keyValuePairObject);
}
}
@@ -0,0 +1,91 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ResourceNotFoundException;
use App\Models\Document;
use App\Models\Transaction;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
class CreateStorageInvoiceTransactionDocProcessor
{
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/**
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
*/
public function __construct(CreatesDocument $createsDocument, CreatesFiles $createsFiles)
{
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
}
/**
* @param Transaction $invoice_transaction
* @throws MalformedRequestException
*/
public function execute(Transaction $invoice_transaction)
{
if($invoice_transaction->status !== ApprovalStatus::COMPLETED){
throw new ResourceNotFoundException();
}
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
Log::info('$dateToCompare 2: '.$dateToCompare);
$storageInvoiceTransactionCreatedDate = Carbon::parse($invoice_transaction->created_at);
Log::info('$storageInvoiceTransactionCreatedDate 2: '.$storageInvoiceTransactionCreatedDate);
if ($storageInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice_transaction->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00'));
if ($storageInvoiceTransactionCreatedDate->isAfter($eInvoiceStartDate)) {
$view = 'pages.pdfs.shipping_invoice_sst_v2';
}
$companyModule = $invoice_transaction->owner->owner->companyModule;
$brn = $companyModule->company->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first();
$documentDate = $invoice_transaction->created_at;
$documentIdentifierPrefix = 'Invoice No: ';
$documentIdentifier = $invoice_transaction->bill_no;
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice_transaction, 'brn' => $brn, 'document_date' => $documentDate, 'document_identifier' => $documentIdentifier, 'document_identifier_prefix' => $documentIdentifierPrefix]);
$document_object = new DocumentObject(
DocumentType::STORAGE_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'storage_invoice'
);
// $invouce_transaction_document = $invoice_transaction->documents()->where('document_type', DocumentType::STORAGE_INVOICE)->first();
// if(!$invouce_transaction_document){
/** @var Document $document */
$document = $this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
// $user = $packingList->owner->companyModule->employees()->first();
// if(app()->environment(['production'])) {
// $user->notify(new InvoiceIssuedEmail($user, $packingList));
// }
// }
}
}
@@ -0,0 +1,39 @@
<?php
namespace App\Classes\Modules\Transactions\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
class CanFetchTransaction extends AbstractRule
{
/**
* @return bool
*/
protected function authorized($object): bool
{
return true;
}
/**
* @param $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -10,4 +10,6 @@ final class AddressType {
public const PICK_UP = 3;
public const E_INVOICE = 4;
}
@@ -25,5 +25,7 @@ final class DocumentType {
public const SHIPPING_INVOICE = 'SHIPPING_INVOICE';
public const STORAGE_INVOICE = 'STORAGE_INVOICE';
public const SALES_ORDER = 'SALES_ORDER';
public const SHIPPING_EINVOICE = 'SHIPPING_EINVOICE';
public const STORAGE_EINVOICE = 'STORAGE_EINVOICE';
}
@@ -0,0 +1,15 @@
<?php
namespace App\Classes\ValueObjects\Constants;
class KVPKey
{
public const EINVOICE_ISSUED = 'EINVOICE_ISSUED';
public const AUTOCOUNT_DOCNO_INVOICE = 'AUTOCOUNT_DOCNO_I';
public const AUTOCOUNT_EINVOICE_VALIDATION_LINK = 'AUTOCOUNT_EINVOICE_VALIDATION_LINK';
public const AUTOCOUNT_DOCNO_OFFICIAL_RECEIPT = 'AUTOCOUNT_DOCNO_OFFICIAL_RECEIPT';
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\ValueObjects\Response;
class RuleEvaluationResult
{
public bool $success = true;
public array $messages = [];
public function __construct(bool $success = true, array $messages = [])
{
$this->success = $success;
$this->messages = $messages;
}
public function failed(): bool
{
return ! $this->success;
}
public function passed(): bool
{
return $this->success;
}
public function messages(): array
{
return $this->messages;
}
}
+4 -22
View File
@@ -7,6 +7,7 @@ use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
use App\Classes\Modules\Transactions\Processors\CreateShippingInvoiceTransactionDocProcessor;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\TransactionType;
@@ -61,29 +62,10 @@ class FixInvoice extends Command
dump($invoice->id);
$invoice->documents()->delete();
// $invoice->documents()->delete();
$invoice->documents()->where('document_type', DocumentType::SHIPPING_EINVOICE)->delete();
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
/** @var Document $document */
$document = (App()->make(CreatesDocument::class))->execute($invoice, $document_object);
(App()->make(CreatesFiles::class))->execute($document, $document_object);
(App()->make(CreateShippingInvoiceTransactionDocProcessor::class))->execute($invoice);
}
}
}
@@ -0,0 +1,50 @@
<?php
namespace App\Console\Commands\V2;
use App\Classes\Jobs\Commands\V2\OneTimeFixWalletGroupTransactionV2CommandJob;
use Illuminate\Console\Command;
class OneTimeFixWalletGroupTransactionV2Command extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'one-time-fix-wallet-group-transaction-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This is a one time fix of unsuccessful group payment through wallet.';
protected $output = null;
protected $outputArray = [];
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
return;
OneTimeFixWalletGroupTransactionV2CommandJob::dispatch();
}
}
@@ -59,7 +59,7 @@ class ProcessYDPortalDataV2Command extends Command
}
foreach ($jobs2 as $index => $job) {
dispatch($job);
dispatch($job)->delay(now()->addSeconds($index * 2));
}
foreach ($jobs3 as $index => $job) {
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Companies;
use App\Classes\Modules\Companies\ControllersLogic\FetchCompanyEInvoiceInfoLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchCompanyEInvoiceInfoController
{
/**
* @param Request $request
* @param FetchCompanyEInvoiceInfoLogic $logic
* @return JsonResponse
*/
public function fetch(Request $request, FetchCompanyEInvoiceInfoLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Companies;
use App\Classes\Modules\Companies\ControllersLogic\UpdateCompanyDetailsLogic;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyDetailsController extends Controller
{
/**
* @param Request $request
* @param UpdateCompanyDetailsLogic $logic
* @return JsonResponse
*/
public function update(Request $request, UpdateCompanyDetailsLogic $logic) : JsonResponse
{
return $logic->execute($request);
}
}
@@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers\Companies;
use App\Classes\Modules\Companies\ControllersLogic\UpdateCompanyEInvoiceInfoLogic;
use App\Classes\Modules\Companies\ControllersLogic\UpdateCompanyEInvoiceRequestLogic;
use App\Classes\Modules\Companies\ControllersLogic\UpdateCompanyEInvoiceRequestChangeLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyEInvoiceInfoController
{
/**
* @param Request $request
* @param UpdateCompanyEInvoiceInfoLogic $logic
* @return JsonResponse
*/
public function updateInfo(Request $request, UpdateCompanyEInvoiceInfoLogic $logic): JsonResponse {
return $logic->execute($request);
}
/**
* @param Request $request
* @param UpdateCompanyEInvoiceRequestLogic $logic
* @return JsonResponse
*/
public function updateRequest(Request $request, UpdateCompanyEInvoiceRequestLogic $logic): JsonResponse {
return $logic->execute($request);
}
/**
* @param Request $request
* @param UpdateCompanyEInvoiceRequestChangeLogic $logic
* @return JsonResponse
*/
public function updateChangeOfMindRequest(Request $request, UpdateCompanyEInvoiceRequestChangeLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -87,7 +87,7 @@ class ExportCompanyModuleSummaryController
}
$exportsAllCustomersInfoForLarkSystem = new ExportsAllCustomersInfoForLarkSystem($request);
$exportFileName = 'all_customers_info_for_lark_system.xls';
$exportFileName = 'shipping_all_customers_info_for_lark_system.xls';
$filesystemDriver = Storage::getDefaultDriver();
if ($filesystemDriver === 's3') {
@@ -0,0 +1,138 @@
<?php
namespace App\Http\Controllers\Exports;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Excel;
use Illuminate\Support\Facades\Storage;
use App\Classes\General\AWSS3Helper;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\Exportable;
use App\Classes\Modules\Exports\Services\ExportsCompanies;
use App\Classes\Modules\Exports\Services\ExportsSalesInvoicesReport;
use App\Classes\Modules\Exports\Services\ExportsReceivePaymentDepositEntryReport;
use App\Classes\Modules\Exports\Services\ExportsReceivePaymentForOrderReport;
use Carbon\Carbon;
class ExportController
{
public function companies(Request $request){
[$startDate, $endDate] = $this->getValidatedDates($request);
$exporter = new ExportsCompanies($startDate, $endDate);
return $this->handleExport($exporter, 'IZYIM - Customers Data Report.xls');
}
public function salesInvoices(Request $request){
[$startDate, $endDate] = $this->getValidatedDates($request);
$exporter = new ExportsSalesInvoicesReport($startDate, $endDate);
//This will merge both paid and unpaid into a single excel sheet
// $exporterA = new ExportsSalesInvoicesReport($startDate, $endDate);
// $exporterB = new ExportsSalesInvoicesReport($startDate, $endDate, true);
// $exporter = $this->buildCombinedInvoices($exporterA, $exporterB);
return $this->handleExport($exporter, 'IZYIM - Sales Invoice Report.xls');
}
public function salesInvoicesUnpaid(Request $request){
[$startDate, $endDate] = $this->getValidatedDates($request);
$exporter = new ExportsSalesInvoicesReport($startDate, $endDate, true);
return $this->handleExport($exporter, 'IZYIM - Sales Invoice Report (unpaid).xls');
}
public function receivePaymentDepositEntry(Request $request){
[$startDate, $endDate] = $this->getValidatedDates($request);
$exporter = new ExportsReceivePaymentDepositEntryReport($startDate, $endDate);
return $this->handleExport($exporter, '11D - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY].xls');
}
public function receivePaymentForOrder(Request $request){
[$startDate, $endDate] = $this->getValidatedDates($request);
$exporter = new ExportsReceivePaymentForOrderReport($startDate, $endDate);
return $this->handleExport($exporter, '11R - IZYIM - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT].xls');
}
private function getValidatedDates(Request $request): array
{
$validated = $request->validate([
'startDate' => 'nullable|date_format:d-m-Y',
'endDate' => 'nullable|date_format:d-m-Y|after_or_equal:startDate',
]);
// $startDate = isset($validated['startDate']) && $validated['startDate']
// ? Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay()
// : Carbon::now()->subMonth()->startOfDay();
// $endDate = isset($validated['endDate']) && $validated['endDate']
// ? Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay()
// : Carbon::now()->endOfDay();
$startDate = isset($validated['startDate']) && $validated['startDate']
? Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay()
: Carbon::now()->startOfMonth()->startOfDay();
$endDate = isset($validated['endDate']) && $validated['endDate']
? Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay()
: Carbon::now()->endOfMonth()->endOfDay();
return [$startDate, $endDate];
}
private function handleExport($exporter, string $exportFileName)
{
$filesystemDriver = Storage::getDefaultDriver();
if ($filesystemDriver === 's3') {
return response([
'src' => AWSS3Helper::S3Exportable($exportFileName, $exporter)
]);
}
$response = $exporter->download(
$exportFileName,
Excel::XLS,
['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
);
ob_end_clean(); // prevent corrupt download in some environments
return $response;
}
private function buildCombinedInvoices($reportA, $reportB)
{
return new class($reportA, $reportB) implements FromCollection, WithHeadings, ShouldAutoSize {
use Exportable;
private $reportA;
private $reportB;
public function __construct($reportA, $reportB)
{
$this->reportA = $reportA;
$this->reportB = $reportB;
}
public function collection()
{
$dataA = $this->reportA->query()->get()->map(function ($row) {
return $this->reportA->map($row);
});
$dataB = $this->reportB->query()->get()->map(function ($row) {
return $this->reportB->map($row);
});
return $dataA->merge($dataB);
}
public function headings(): array
{
return $this->reportA->headings();
}
};
}
}

Some files were not shown because too many files have changed in this diff Show More