Compare commits

...

216 Commits

Author SHA1 Message Date
Edmond Lang 4d79571f48 order profile pagination 2025-07-03 10:26:24 +08:00
Edmond Lang ff86009ddf order profile pagination 2025-07-03 10:05:51 +08:00
Edmond Lang 928593e32d order profile pagination 2025-07-03 00:59:56 +08:00
Edmond Lang 56802de67f order profile pagination 2025-07-03 00:41:48 +08:00
Edmond Lang 912324cac9 order profile pagination 2025-07-03 00:05:54 +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 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 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 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
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 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
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
Edmond Lang d6cfd85aa2 add /export/all-customers-info-for-lark-system 2025-06-12 22:18:53 +08:00
Dillon Ngo 844527417a Quick fix problem reported by GaryHoo - IZYIM order order quantity is different 2025-05-27 20:04:42 +08:00
Dillon Ngo f725933f7e Quick fix problem reported by Yien - IZYIM unable to claim unclaimed packing list, after key in the correct order number and click confirm, there is no response 2025-05-27 19:37:44 +08:00
Dillon Ngo d5a5f9e730 UI/UX + syntax fix 2025-05-13 11:33:58 +08:00
Dillon Ngo 62f892dfd1 UI/UX + syntax fix 2025-05-13 04:34:58 +08:00
Dillon Ngo 82f5d4c2bc UI/UX + syntax fix 2025-05-13 04:09:36 +08:00
Dillon Ngo a1eebe7f65 UI/UX + syntax fix 2025-05-13 02:45:40 +08:00
Edmondlang 18bd36217b add function to add contact person 2025-05-06 11:16:06 +08:00
Dillon Ngo 772fd583b5 Quick patch for missing parcel from YD integration reported by Yan - case number 2 on 20250502 2025-05-02 21:21:50 +08:00
Dillon Ngo 57812656fd Quick patch for missing parcel from YD integration reported by Yan - case number 2 on 20250502 2025-05-02 21:02:51 +08:00
Dillon Ngo 3933728a19 Quick patch for missing parcel from YD integration reported by Yan - case number 2 on 20250502 2025-05-02 20:47:01 +08:00
Dillon Ngo 8ce8ed813a Quick patch for missing parcel from YD integration reported by Yan - using command 2025-05-01 18:56:12 +08:00
Dillon Ngo 50b2f00bdc Merge branch 'dillon/83-yd-order-tracking-query-ui' into vapor/production 2025-04-28 22:24:11 +08:00
Dillon Ngo 54c23c9f38 New UI to show YD Order Tracking infomation - Disable unit testing for production deployment 2025-04-28 22:23:53 +08:00
Dillon Ngo 15570de9fb Merge branch 'dillon/83-yd-order-tracking-query-ui' into vapor/production 2025-04-28 22:20:55 +08:00
Edmondlang b21cdba5ae upon payment completion, need to redirect to order.show instead of order.details 2025-04-28 16:05:54 +08:00
Edmondlang fe8395b250 Yien's request: remove the MXXXXXXXX below the order number? we shouldn't show it to customer 2025-04-25 10:28:18 +08:00
Dillon Ngo 61f01ed39b New UI to show YD Order Tracking infomation - Testing 2025-04-24 12:35:32 +08:00
Dillon Ngo 6e2b2e5f65 New UI to show YD Order Tracking infomation - Harry feedback update 2025-04-23 12:48:41 +08:00
Dillon Ngo b4b509b0d1 New UI to show YD Order Tracking infomation - Harry feedback update 2025-04-23 12:39:43 +08:00
Dillon Ngo 6bafc49a22 New UI to show YD Order Tracking infomation - Testing 2025-04-19 19:46:00 +08:00
Edmondlang 4e4bf96a07 revert exportGroupTransaction. Wrong updates 2025-04-18 10:18:30 +08:00
Edmondlang 2e9c3000a6 remove the time from the "Date" column
Request from Azril:

I’ve attached 3 files below:
AutoMapping Excel – downloaded from the Exchange Portal
Paid Invoice Excel – from the IzyIM Portal
Aging Report Excel – also from the IzyIM Portal
What we need from you is to remove the time from the "Date" column in each file. We only need the date value moving forward.
2025-04-17 18:31:38 +08:00
Dillon Ngo 3e4d52d2ff New UI to show YD Order Tracking infomation - fixes for feedback on 20250408 2025-04-16 22:17:20 +08:00
Dillon Ngo f25f5ebb41 New UI to show YD Order Tracking infomation - fixes for feedback on 20250408 2025-04-16 22:13:50 +08:00
Edmondlang 404758c851 fix bug : Error: ob_end_clean(): failed to delete buffer.
use AWSS3Helper if filesystemDriver = s3
2025-04-16 18:18:08 +08:00
Edmondlang f6d00383cb Safely clean output buffer only if it's started and not already cleaned 2025-04-16 14:40:07 +08:00
Edmondlang 33dfdde9a0 Error: ob_end_clean(): failed to delete buffer. No buffer to delete.
Fix: Safely clean output buffer if it exists
2025-04-16 10:56:21 +08:00
Edmondlang 9b1a5b633c code update for: add function to change mobile no 2025-04-15 20:13:50 +08:00
Edmondlang b0cd0cca4d remove the time from the "Date" column
Request from Azril:

I’ve attached 3 files below:
AutoMapping Excel – downloaded from the Exchange Portal
Paid Invoice Excel – from the IzyIM Portal
Aging Report Excel – also from the IzyIM Portal
What we need from you is to remove the time from the "Date" column in each file. We only need the date value moving forward.
2025-04-15 19:49:26 +08:00
Edmondlang c0e60e5d3b add function to change mobile no 2025-04-15 19:24:11 +08:00
Dillon Ngo d093b774c2 New UI to show YD Order Tracking infomation - Testing 2025-04-14 15:29:21 +08:00
Dillon Ngo 3fa4b498e9 New UI to show YD Order Tracking infomation - Testing 2025-04-14 15:14:44 +08:00
Dillon Ngo ccd06ff740 New UI to show YD Order Tracking infomation - Testing 2025-04-14 13:53:22 +08:00
Dillon Ngo c209f6e4ed New UI to show YD Order Tracking infomation - Testing 2025-04-14 12:58:00 +08:00
Dillon Ngo f4d8ece23f New UI to show YD Order Tracking infomation - Testing 2025-04-14 12:44:50 +08:00
Dillon Ngo 215e4c72d3 New UI to show YD Order Tracking infomation - Testing 2025-04-14 12:20:54 +08:00
Dillon Ngo 386f5740f4 New UI to show YD Order Tracking infomation - Testing 2025-04-14 10:20:09 +08:00
Dillon Ngo 78c43fd7a4 New UI to show YD Order Tracking infomation - Testing 2025-04-14 10:05:45 +08:00
edmondlang d076892176 invoice date in the order payment section is wrong. It should be created_at date 2025-04-09 17:21:52 +08:00
Dillon Ngo 06b9695528 New UI to show YD Order Tracking infomation - Testing 2025-04-03 09:58:01 +08:00
Dillon Ngo 0a54f46b91 New UI to show YD Order Tracking infomation - Testing 2025-04-03 09:49:58 +08:00
Dillon Ngo 83b3d0c725 New UI to show YD Order Tracking infomation - Testing 2025-04-03 09:42:13 +08:00
Dillon Ngo de7331547c New UI to show YD Order Tracking infomation - Testing 2025-04-03 09:38:17 +08:00
Dillon Ngo 4daaac476d New UI to show YD Order Tracking infomation - Testing 2025-04-03 09:26:05 +08:00
Dillon Ngo fbf036d4b8 New UI to show YD Order Tracking infomation 2025-04-03 08:02:18 +08:00
Dillon Ngo 055e720e9f New UI to show YD Order Tracking infomation 2025-04-03 07:18:31 +08:00
Dillon Ngo 5a0b2d5a86 New UI to show YD Order Tracking infomation 2025-03-25 07:02:01 +08:00
Dillon Ngo 8f6f9893bb New UI to show YD Order Tracking infomation 2025-03-25 06:57:50 +08:00
Dillon Ngo 3255020f11 New UI to show YD Order Tracking infomation 2025-03-25 06:54:44 +08:00
Dillon Ngo 8c16277c6c New UI to show YD Order Tracking infomation 2025-03-25 06:36:32 +08:00
Dillon Ngo 87aeb0ae59 New UI to show YD Order Tracking infomation 2025-03-25 06:28:10 +08:00
Dillon Ngo 76b14cd667 New UI to show YD Order Tracking infomation 2025-03-25 06:24:43 +08:00
Dillon Ngo 6affa86c92 Quick patch for missing YD integration - using web route 2025-03-25 03:59:43 +08:00
Dillon Ngo a8c4661b2d New UI to show YD Order Tracking infomation 2025-03-24 06:40:55 +08:00
Dillon Ngo acb42ef3ab New UI to show YD Order Tracking infomation 2025-03-24 05:48:00 +08:00
Dillon Ngo 21f1a14e6f New UI to show YD Order Tracking infomation 2025-03-24 05:20:53 +08:00
Dillon Ngo d5a9e3923e New UI to show YD Order Tracking infomation 2025-03-22 11:39:31 +08:00
Dillon Ngo 7416aa00ac Quick patch for missing YD integration - using web route 2025-03-21 09:21:01 +08:00
Dillon Ngo 437765bdbb Quick patch for missing YD integration - using web route 2025-03-19 09:01:05 +08:00
Dillon Ngo 9c7ed93a54 Quick patch for missing YD integration 2025-03-18 12:31:02 +08:00
edmondlang a3b08a7c11 fix bug error web "/container/billing/{month}/{year}" 2025-02-17 17:43:52 +08:00
edmondlang e3bc918bd8 add new segment - No Extra Centimeter Charged 2025-02-14 00:30:53 +08:00
Dillon Ngo a23a632b87 Debug approve payment problem 2025-02-01 21:31:32 +08:00
Dillon Ngo 651092aa65 Debug approve payment problem 2025-02-01 21:09:44 +08:00
Dillon Ngo fe79d5bcef Debug approve payment problem 2025-02-01 19:01:24 +08:00
Dillon Ngo 6ea7517187 Debug approve payment problem 2025-02-01 18:45:05 +08:00
Dillon Ngo 4e68eefe4d Debug approve payment problem 2025-02-01 18:21:03 +08:00
Dillon Ngo 48fc02f2d2 Debug approve payment problem 2025-02-01 18:00:12 +08:00
Dillon Ngo 942c94c821 Debug approve payment problem 2025-02-01 02:20:10 +08:00
Dillon Ngo bfb76bc512 Debug approve payment problem 2025-02-01 02:00:07 +08:00
Dillon Ngo 8e3cdef4e1 Debug approve payment problem 2025-02-01 01:04:15 +08:00
Dillon Ngo c798d96238 Debug approve payment problem 2025-02-01 00:40:52 +08:00
Dillon Ngo 64d1b91fa3 Debug approve payment problem 2025-01-31 23:51:15 +08:00
Dillon Ngo 2ff63c8d0d Debug approve payment problem 2025-01-31 23:26:52 +08:00
Dillon Ngo b57a7cb2bb Debug approve payment problem 2025-01-31 23:07:20 +08:00
Dillon Ngo bf5c5574d6 Debug approve payment problem 2025-01-31 22:34:45 +08:00
Dillon Ngo 74a1f2af4c Debug approve payment problem 2025-01-31 22:11:03 +08:00
Dillon Ngo 95d230d64f Debug approve payment problem 2025-01-31 21:58:16 +08:00
Dillon Ngo 88564c661f Debug approve payment problem 2025-01-31 21:33:14 +08:00
edmondlang 6ce7f7dc91 add Google Tag Manager (GTM) so that the chat daddy code can work 2025-01-21 13:08:14 +08:00
edmondlang b91a8635d5 disable crisp 2025-01-21 12:36:19 +08:00
edmondlang 236b3769f8 add more district in seeder 2025-01-21 12:35:16 +08:00
edmondlang 3c4a19d4be update order Resource 2024-12-17 18:03:43 +08:00
edmondlang 269fbcbd66 revert logging for UpdateDoFromYDPortalProcessor response 2024-12-16 14:33:32 +08:00
edmondlang 603a67c770 add created_at for ExportsSegmentCustomers 2024-12-16 13:16:32 +08:00
edmondlang bb0832b8b0 add logging for UpdateDoFromYDPortalProcessor response 2024-12-16 12:22:29 +08:00
Dillon Ngo 8276fef3e1 YD API - Added logs for debugging 2024-12-15 09:46:54 +08:00
edmondlang aa4fcae07e update export segment customers 2024-12-13 20:34:32 +08:00
edmondlang 05adf091a8 update export segment customers 2024-12-13 20:00:07 +08:00
edmondlang b5e5e88a6a export segment customers 2024-12-13 18:41:11 +08:00
Dillon Ngo 32bad3bf07 Data patch for order already PAID, but still showing unpaid 2024-12-11 02:19:48 +08:00
edmondlang 1508fb5f1a add new advertisement - Tax Refund Service 2024-11-29 20:46:14 +08:00
edmondlang 70a2bdec48 change all 'Tax Rebate' to 'Tax Refund' 2024-11-26 19:05:01 +08:00
Dillon Ngo f5df0c9f1f Merge branch 'dillon/34.8b-yd-api-bug-fix' into vapor/production 2024-11-26 15:58:51 +08:00
Dillon Ngo e50bab014d Laravel Vapor - Fix a problem where packages not updating correct status 2024-11-26 15:58:31 +08:00
edmondlang 1933787fc3 addd function to revert identification document approval 2024-11-21 14:46:22 +08:00
Dillon Ngo 5535f13aff Merge branch 'dillon/34.8a-enhancement' into vapor/production 2024-11-18 20:56:19 +08:00
Dillon Ngo 3a2131a04d Laravel Vapor - Enhancement to prevent customer from underpay when a payment transaction include storage invoice(s) 2024-11-17 13:51:54 +08:00
Dillon Ngo c8e8c9cb0e Merge branch 'dillon/34.8b-yd-api-bug-fix' into vapor/production 2024-11-16 15:49:18 +08:00
Dillon Ngo 0e617f5ce2 Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-16 15:49:00 +08:00
Dillon Ngo ccb77ce56c Merge branch 'dillon/34.8b-yd-api-bug-fix' into vapor/production 2024-11-16 14:29:21 +08:00
Dillon Ngo 8f8c3ca660 Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-16 14:28:43 +08:00
Dillon Ngo 922718f7c2 Laravel Vapor - Enhancement to prevent customer from underpay when a payment transaction include storage invoice(s) 2024-11-16 09:17:15 +08:00
Dillon Ngo 54e6041fe5 Laravel Vapor - Enhancement to prevent customer from underpay when a payment transaction include storage invoice(s) 2024-11-15 18:34:08 +08:00
Dillon Ngo 141f1ed9d5 Laravel Vapor - Enhancement to prevent customer from underpay when a payment transaction include storage invoice(s) 2024-11-15 09:17:16 +08:00
Dillon Ngo 61d7ad22e7 Laravel Vapor - Enhancement to prevent customer from underpay when a transaction also invoice storage invoices 2024-11-14 14:03:29 +08:00
Dillon Ngo 798bf4e70e Merge branch 'dillon/34.8b-yd-api-bug-fix' into vapor/production 2024-11-14 12:02:24 +08:00
Dillon Ngo aa833f7a9f Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-14 11:48:26 +08:00
Dillon Ngo 8dd3fbf97a Merge branch 'dillon/34.8b-yd-api-bug-fix' into vapor/production 2024-11-13 21:38:36 +08:00
Dillon Ngo 63e1b767fc Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-13 21:37:20 +08:00
Dillon Ngo 60ff1c5130 Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-13 21:36:56 +08:00
Dillon Ngo 22aac2df04 Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-13 10:54:17 +08:00
edmondlang 33d65be53b tax rebate feedback:
1. add the word "退税“ behind the order number as requested by YD
2. the word "供应商” should change to “联络人”
3, Tax Rebate Refund only applicable on GZ warehouse. YW and FS warehouse cannot do Tax Rebate. Can you block or disallow the tax rebate section for this both warehouse ?
4. It will be good if a delete button can be implemented in the Created Tax Rebate QR code, so customer can remove them if they created wrongly
2024-11-13 00:18:16 +08:00
Dillon Ngo d2f6f4e8a1 Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-12 17:45:01 +08:00
Dillon Ngo 299c384cb2 Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-12 13:48:06 +08:00
Dillon Ngo be171f550b Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-12 12:18:07 +08:00
Dillon Ngo 8295b80f73 Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-11-12 09:24:09 +08:00
Dillon Ngo 67969c63d3 Laravel Vapor - Logs output minor amendments (code sync with Exchange) 2024-11-12 09:05:45 +08:00
Dillon Ngo 2074c8661a Laravel Vapor - Remove comments 2024-11-12 08:01:59 +08:00
Dillon Ngo 9518928b7d Laravel Vapor - Remove comments 2024-11-12 07:59:38 +08:00
Dillon Ngo 634a39b1ea Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-11-11 15:08:14 +08:00
Dillon Ngo 5808fd0b2f Laravel Vapor - Fix missing info with order packages where in China Warehoue 2024-11-11 15:06:30 +08:00
Dillon Ngo d7ce1df29b Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-11 15:01:31 +08:00
Dillon Ngo eac3f31351 Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-11 14:48:05 +08:00
Dillon Ngo 95a9cba32d Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-11 13:22:28 +08:00
Dillon Ngo 26812f723a Laravel Vapor - YD API integration code rewrite to fix eta/etd 2024-11-11 12:48:52 +08:00
edmondlang 0734447937 fix bug - /orders search component not working 2024-11-06 18:38:48 +08:00
Dillon Ngo e3f57fffd6 Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-11-05 04:21:27 +08:00
Dillon Ngo b4bc441a5b Laravel Vapor - Update custom logs retention period (sync code from Exchange) 2024-11-05 04:09:08 +08:00
Dillon Ngo d678440032 Laravel Vapor - Update custom logs retention period (sync code from Exchange) 2024-11-05 03:28:17 +08:00
edmondlang 4f95520826 Merge branch 'vapor/production' of https://gitlab.com/CIEFWorldwideSdnBhd/shipping-portal into vapor/production 2024-11-04 16:46:22 +08:00
edmondlang 33a271a54c fix bug - /orders search component not working 2024-11-04 16:45:59 +08:00
Dillon Ngo 3e3728a089 Laravel Vapor - move certain environment variables to source code vapor YAML file 2024-11-02 07:04:29 +08:00
Dillon Ngo dc8a1b0325 Merge branch 'dillon/34.8a-enhancement' into vapor/production 2024-11-02 06:08:31 +08:00
edmondlang 4a6e5f7130 fix bug create order add address extra fields 2024-11-01 17:27:55 +08:00
Dillon Ngo 6b78ca3d46 Laravel Vapor - move certain environment variables to source code vapor YAML file 2024-11-01 11:18:47 +08:00
Dillon Ngo 38612253d0 Laravel Vapor - move certain environment variables to source code vapor YAML file 2024-11-01 11:00:41 +08:00
Dillon Ngo 2fccdf4f7e Laravel Vapor - Enhancement to prevent customer from underpay when a transaction also invoice storage invoices 2024-11-01 10:05:16 +08:00
edmondlang 56d48598df deploy tax rebate QR and address extra fields 2024-10-31 18:13:10 +08:00
edmondlang 4f77da822b Merge branch 'vapor-address-extra-fields' of https://gitlab.com/CIEFWorldwideSdnBhd/shipping-portal into vapor/production 2024-10-31 18:05:50 +08:00
edmondlang cf6fd2dad9 Merge branch 'vapor/tax-rebate-qr' of https://gitlab.com/CIEFWorldwideSdnBhd/shipping-portal into vapor/production 2024-10-31 18:05:35 +08:00
Dillon Ngo 6cb1ec82f3 Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-10-30 12:42:36 +08:00
Dillon Ngo 733b9cdfcc Laravel Vapor - sync code from Exchange date filter for reports download at /downloads page 2024-10-30 12:24:50 +08:00
Dillon Ngo 4a2860449f Laravel Vapor - Enhancement to prevent customer from underpay when a transaction also invoice storage invoices 2024-10-30 10:02:18 +08:00
Dillon Ngo 6fbea32761 Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-10-23 03:06:31 +08:00
Dillon Ngo 50624b3d75 Laravel Vapor - Debug YD API call 2024-10-23 03:06:24 +08:00
Dillon Ngo dddbeb2ebd Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-10-23 01:37:26 +08:00
Dillon Ngo 22714a2763 Laravel Vapor - Debug YD API call 2024-10-23 01:37:01 +08:00
edmondlang bc2c9610ee update tax rebate qr 2024-10-22 23:50:44 +08:00
edmondlang 3dc234321c update tax rebate qr 2024-10-22 23:29:51 +08:00
edmondlang 4a65031aa3 tax rebate qr 2024-10-22 22:58:06 +08:00
Dillon Ngo 4dd30b29c0 Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-10-19 03:17:35 +08:00
Dillon Ngo ac6211cf5f Laravel Vapor - FIx a problem where order page not showing any thing 2024-10-19 03:17:20 +08:00
Dillon Ngo 65a622cd7b Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-10-19 02:07:24 +08:00
Dillon Ngo bba600725e Laravel Vapor - Data patch for underpay group payments 2024-10-19 01:07:58 +08:00
Dillon Ngo 4fa80a2a88 Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-10-18 12:15:49 +08:00
Dillon Ngo 64f52f2c11 Laravel Vapor - FIx a problem where order page not showing any thing 2024-10-18 12:15:35 +08:00
Dillon Ngo 72c1b2fb2e Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-10-16 03:52:39 +08:00
Dillon Ngo b4f5328a21 Laravel Vapor - Minor typo error amendment 2024-10-16 03:23:05 +08:00
Dillon Ngo 7aee324294 Merge branch 'dillon/34.8-jenkins-vapor' into vapor/production 2024-10-16 01:51:40 +08:00
Dillon Ngo 7930e45393 Laravel Vapor - Update new RDS endpoint 2024-10-16 01:51:18 +08:00
Dillon Ngo 052dc4e5a0 Merge branch 'dillon/34.7-jenkins-vapor' into vapor/production 2024-10-16 01:21:43 +08:00
Dillon Ngo 450d2c15f9 Laravel Vapor - Update new RDS Instance endpoint 2024-10-13 16:28:52 +08:00
Dillon Ngo 7b6ed51ce8 Laravel Vapor - New website under maintenance page 2024-10-12 23:50:22 +08:00
Dillon Ngo 30d99b8d79 Laravel Vapor - New website under maintenance page 2024-10-12 23:22:01 +08:00
Dillon Ngo e6db981d5e Laravel Vapor - New UI for admin to download reports 2024-10-12 14:58:41 +08:00
Dillon Ngo d4e008380b Laravel Vapor - New UI for admin to download reports 2024-10-12 14:44:15 +08:00
191 changed files with 7723 additions and 552 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."
+30
View File
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Site Under Maintenance</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
text-align: center;
padding: 50px;
}
.content {
background: white;
padding: 20px;
border-radius: 10px;
display: inline-block;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<div class="content">
<h1>We'll be back soon!</h1>
<p>Sorry for the inconvenience but we're performing some maintenance at the moment. We'll be back online shortly!</p>
<p>&mdash; CIEF IZYIM</p>
</div>
</body>
</html>
Vendored
+13
View File
@@ -17,6 +17,9 @@ pipeline {
}
environment {
HOME = '.'
DB_CONNECTION = 'mysql'
DB_DATABASE = 'portal_development'
APP_ENV = 'testing'
}
stages {
stage('Download source code from Git') {
@@ -59,6 +62,16 @@ pipeline {
stage('Tests') {
steps {
//sh 'vendor/bin/phpunit tests/Unit'
withCredentials([
usernamePassword(
credentialsId: 'shipping-portal-dev-db-credential',
usernameVariable: 'DB_USERNAME',
passwordVariable: 'DB_PASSWORD'
),
string(credentialsId: 'shipping-portal-dev-db-host', variable: 'DB_HOST')
]) {
// sh 'vendor/bin/phpunit --filter ListOrderTrackingLogicTest'
}
script{
currentBuild.description = 'Step 4 of 6 Completed'
}
@@ -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,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class OrderTrackingId implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('order_tracking_id', $value);
}
}
@@ -23,6 +23,7 @@ class PackingListLimitOneByTypeOrderedByInvoiceDate 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');
$join->whereRaw('(transactions.type <> 16 OR transactions.id = (
SELECT id FROM transactions WHERE owner_id = packing_lists.id AND type = 16 LIMIT 1
))');
@@ -0,0 +1,23 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class TrackingNo implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('tracking_no', $value)
->where(function ($query) {
$query->whereNotNull('tracking_english')
->orWhereNotNull('remark_english');
});
}
}
@@ -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);
}
}
+15 -3
View File
@@ -19,7 +19,11 @@ class LogHelper
{
$envVar = env('LARAVEL_VAPOR_ENABLED');
$isLocal = env('VAPOR_ENV') === 'local';
Log::info("LogHelper.info: {$message} channelName {$this->channelName}, envVar {$envVar}");
if($envVar)
{
Log::info("Info: {$message} channelName {$this->channelName}, envVar {$envVar}");
}
if ($envVar && !$isLocal) {
Log::channel($this->channelName.'_vapor')->info($message);
}
@@ -32,7 +36,11 @@ class LogHelper
{
$envVar = env('LARAVEL_VAPOR_ENABLED');
$isLocal = env('VAPOR_ENV') === 'local';
Log::info("LogHelper.warning: {$message} channelName {$this->channelName}, envVar {$envVar}");
if($envVar)
{
Log::info("Warning: {$message} channelName {$this->channelName}, envVar {$envVar}");
}
if ($envVar && !$isLocal) {
Log::channel($this->channelName . '_vapor')->warning($message);
} else {
@@ -44,7 +52,11 @@ class LogHelper
{
$envVar = env('LARAVEL_VAPOR_ENABLED');
$isLocal = env('VAPOR_ENV') === 'local';
Log::info("LogHelper.error: {$message} channelName {$this->channelName}, envVar {$envVar}");
if($envVar)
{
Log::info("Error: {$message} channelName {$this->channelName}, envVar {$envVar}");
}
if ($envVar && !$isLocal) {
Log::channel($this->channelName . '_vapor')->error($message);
} else {
@@ -0,0 +1,61 @@
<?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\Billplzs\Processors\CallbackBillplzProcessor;
use App\Classes\Modules\Documents\Services\ApprovesDocument;
use App\Classes\Modules\Documents\Services\RejectsDocument;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Group;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class FixPaymentApprovalTimedOutErrorV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
Log::info(Carbon::now() . ': Start job - Fix payment approval timed out error (status 504: Endpoint request timed out).');
$start = new Carbon();
$status= 'approve';
$transactionId = 23160;
$transaction = (App()->make(FetchesTransaction::class))->execute(['id' => $transactionId]);
$document = $transaction->documents()
->where('status', ApprovalStatus::PENDING_VERIFICATION)
->first();
Log::info("FixApprovedPaymentFailedGroupV2CommandJob document: ".json_encode($document));
if($status === 'approve') {
// (App()->make(ApprovesDocument::class))->execute($document);
$document->status = ApprovalStatus::APPROVED;
// $document->approver = Auth()->user()->id;
$document->approval_date = Carbon::now();
$document->save();
}
else {
(App()->make(RejectsDocument::class))->execute($document);
}
(App()->make(UpdatesTransactionStatus::class))->execute($transaction, $status === 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED);
if ($status === 'approve') {
(App()->make(CallbackBillplzProcessor::class))->execute($transaction, ApprovalStatus::APPROVED);
}
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - Fix payment approval timed out error (status 504: Endpoint request timed out). ElapsedTime: ' . $elapsedTime . '.');
}
}
@@ -8,6 +8,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Classes\Modules\Billplzs\Processors\CallbackBillplzProcessor;
use App\Classes\Modules\Billplzs\Processors\CallbackBillplzDataPatchProcessor;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Transaction;
@@ -19,26 +20,26 @@ class OneTimeTransactionFixBillplzFailedCbV2CommandJob implements ShouldQueue
public function handle()
{
Log::info(Carbon::now() . ': Start job - One time fix failled callback from billplz for transaction with id 17310 cron ended.');
Log::info(Carbon::now() . ': Start job - One time fix failled callback from billplz cron ended.');
$start = new Carbon();
// ini_set('memory_limit', '-1');
//Transaction fix with this one time fix command: 15205, 16803, 17310
//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
$transaction = Transaction::whereIn('id', [17310])->first();
Log::info(Carbon::now() . ' : One time fix failled callback from billplz for transaction with id 17310 cron started.');
$transactions = Transaction::whereIn('id', [22008, 6770])->get();
Log::info(Carbon::now() . ' : One time fix failled callback from billplz started.');
if($transaction && $transaction->id == 17310){
foreach ($transactions as $transaction){
if($transaction){
Log::info(Carbon::now() . ' : 17310.');
$status = ApprovalStatus::APPROVED;
// $this->callbackBillplzProcessor->execute($transaction, $status);
(App()->make(CallbackBillplzDataPatchProcessor::class))->execute($transaction, $status);
Log::info(Carbon::now() . ' : '.$transaction->id);
$status = ApprovalStatus::APPROVED;
(App()->make(CallbackBillplzProcessor::class))->execute($transaction, $status);
// (App()->make(CallbackBillplzDataPatchProcessor::class))->execute($transaction, $status);
}
}
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
Log::info(Carbon::now() . ': End job - One time fix failled callback from billplz for transaction with id 17310 cron ended. ElapsedTime: ' . $elapsedTime . '.');
Log::info(Carbon::now() . ': End job - One time fix failled callback from billplz cron ended. ElapsedTime: ' . $elapsedTime . '.');
}
}
@@ -0,0 +1,31 @@
<?php
namespace App\Classes\Jobs\Commands\V2\YD;
use App\Classes\Modules\PackingLists\Processors\V2\FetchByTrakingNoYdPortalV2Processor;
use App\Models\PackingList;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class FetchTrakingInfoYDByPackingListV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $packingList;
public function __construct(PackingList $packingList)
{
$this->packingList = $packingList;
}
public function handle()
{
Log::info('Processing FetchTrakingInfoYDByPackingListV2CommandJob');
$processor = app(FetchByTrakingNoYdPortalV2Processor::class);
$processor->execute($this->packingList);
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\Jobs\Commands\V2\YD;
use App\Classes\Modules\PackingLists\Processors\V2\FetchByTrakingNoYdPortalV2Processor;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class FetchTrakingInfoYDByTrackingNoV2CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $trackingNo;
public function __construct(string $trackingNo)
{
$this->trackingNo = $trackingNo;
}
public function handle()
{
Log::info('Processing FetchTrakingInfoYDByTrackingNoV2CommandJob');
$processor = app(FetchByTrakingNoYdPortalV2Processor::class);
$processor->processTrackingNo($this->trackingNo);
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\Jobs\Commands\V2\YD;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Artisan;
class ProcessYDByTrakingNoDataV2Job implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $trackingNo;
public function __construct($trackingNo)
{
$this->trackingNo = $trackingNo;
}
public function handle()
{
Artisan::call('process-yd-by-traking-no-data-command', [
'trackingNo' => $this->trackingNo
]);
}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Classes\Jobs\Commands\V2\YD;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Artisan;
class ProcessYDPortalDataV2Job implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $start;
protected $end;
public function __construct($start, $end)
{
$this->start = $start;
$this->end = $end;
}
public function handle()
{
Artisan::call('process-yd-portal-data-command', [
'start_date' => $this->start,
'end_date' => $this->end
]);
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\Jobs\Commands\V3\YD;
use App\Classes\Modules\PackingLists\Processors\V3\FetchContainersUpdatesYdPortalV3Processor;
use App\Models\Container;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class FetchContainersUpdatesYdPortalV3CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
}
public function handle()
{
Log::info('Processing FetchContainersUpdatesYdPortalV3CommandJob');
$processor = app(FetchContainersUpdatesYdPortalV3Processor::class);
$processor->execute($this->container);
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\Jobs\Commands\V3\YD;
use App\Classes\Modules\PackingLists\Processors\V3\FetchContainersYdPortalV3Processor;
use App\Models\PackingList;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class FetchContainersYdPortalV3CommandJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $packingList;
public function __construct(PackingList $packingList)
{
$this->packingList = $packingList;
}
public function handle()
{
Log::info('Processing FetchContainersYdPortalV3CommandJob');
$processor = app(FetchContainersYdPortalV3Processor::class);
$processor->execute($this->packingList);
}
}
@@ -15,8 +15,10 @@ use App\Classes\Modules\Contacts\Processors\CreateContactProcessor;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Classes\Modules\Remarks\Processors\CreateRemarkProcessor;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\RemarkTypes;
use App\Http\Resources\AddressResource;
use App\Models\Address;
use Carbon\Carbon;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -100,6 +102,24 @@ class CreateAddressLogic extends AbstractControllerLogic
$this->createRemarkProcessor->execute($address, $remarkObject);
}
if ($request->input('pickup_time_to') <= $request->input('pickup_time_from')) {
$pickupTimeFrom = Carbon::parse($request->input('pickup_time_from'));
$request->merge([
'pickup_time_to' => $pickupTimeFrom->addHour()->format('H:i') // Format to hh:mm
]);
}
$addressExtraFields = [
'property_type' => $request->input('property_type'),
'receive_goods_working_hours' => $request->input('receive_goods_working_hours'),
'receive_goods_after_hours' => $request->input('receive_goods_after_hours'),
'receive_goods_on_saturday' => $request->input('receive_goods_on_saturday'),
];
$address->addressExtraFields()->delete();
$addressExtraFieldsObject = new RemarkObject(json_encode($addressExtraFields), Auth()->user()->id, RemarkTypes::ADDRESS_EXTRA_COLUMNS);
$remark = $this->createRemarkProcessor->execute($address, $addressExtraFieldsObject);
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);
}
}
@@ -88,14 +88,14 @@ class CallbackBillplzDataPatchProcessor
$invoice = $groupTransaction->transaction;
Log::info('CallbackBillplzDataPatchProcessor 3: '.json_encode($invoice));
//if($invoice->status !== ApprovalStatus::COMPLETED){
// $paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, null, false);
if($invoice->status !== ApprovalStatus::COMPLETED){
$paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, null, false);
// if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
$pL = $invoice->owner;
$this->releaseGoodsToCustomerProcessor->execute($pL, $invoice, true);
//}
//}
}
}
}
$group->status = $status;
@@ -8,15 +8,12 @@ use App\Classes\Modules\Documents\Standards\Rules\CanApproveDocument;
use App\Classes\Modules\Orders\Services\UpdatesOrdersStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Http\Resources\DocumentResource;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Documents\Services\FetchesDocument;
use App\Classes\Modules\Documents\Services\ApprovesDocument;
use App\Classes\Modules\Documents\Services\PendingVerificationDocument;
use App\Classes\Modules\Notifications\DataTransferObjects\NotificationObject;
Use App\Classes\Modules\Notifications\Processors\CreateNotificationProcessor;
use App\Classes\Modules\Notifications\Processors\CreateNotificationProcessor;
use App\Models\Document;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -27,10 +24,11 @@ class ApproveIdentificationDocumentLogic extends AbstractControllerLogic
/**
* @return array
*/
protected function notification():array {
protected function notification(): array
{
return [
'title' => 'Approve Document',
'message' => 'You have successfully approved the Document'
'title' => 'Update Document Status',
'message' => 'You have successfully updated the Document Status'
];
}
@@ -43,6 +41,9 @@ class ApproveIdentificationDocumentLogic extends AbstractControllerLogic
/** @var RejectsDocument */
private $rejectsDocument;
/** @var PendingVerificationDocument */
private $pendingVerificationDocument;
/** @var FetchesDocument */
private $fetchesDocument;
@@ -61,11 +62,12 @@ class ApproveIdentificationDocumentLogic extends AbstractControllerLogic
* @param ApprovesDocument $approvesDocument
* @param RejectsDocument $rejectsDocument
* @param FetchesDocument $fetchesDocument
* @param PendingVerificationDocument $pendingVerificationDocument
* @param UpdatesCompanyStatus $updatesCompanyStatus
* @param UpdatesOrdersStatus $updatesOrdersStatus
* @param CreateNotificationProcessor $createNotificationProcessor
*/
public function __construct(CanApproveDocument $canApproveDocument, ApprovesDocument $approvesDocument, RejectsDocument $rejectsDocument, FetchesDocument $fetchesDocument, UpdatesCompanyStatus $updatesCompanyStatus, UpdatesOrdersStatus $updatesOrdersStatus, CreateNotificationProcessor $createNotificationProcessor)
public function __construct(CanApproveDocument $canApproveDocument, ApprovesDocument $approvesDocument, RejectsDocument $rejectsDocument, FetchesDocument $fetchesDocument, UpdatesCompanyStatus $updatesCompanyStatus, UpdatesOrdersStatus $updatesOrdersStatus, CreateNotificationProcessor $createNotificationProcessor, PendingVerificationDocument $pendingVerificationDocument)
{
$this->canApproveDocument = $canApproveDocument;
$this->approvesDocument = $approvesDocument;
@@ -74,6 +76,7 @@ class ApproveIdentificationDocumentLogic extends AbstractControllerLogic
$this->updatesCompanyStatus = $updatesCompanyStatus;
$this->updatesOrdersStatus = $updatesOrdersStatus;
$this->createNotificationProcessor = $createNotificationProcessor;
$this->pendingVerificationDocument = $pendingVerificationDocument;
}
/**
@@ -83,37 +86,37 @@ class ApproveIdentificationDocumentLogic extends AbstractControllerLogic
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
public function logic(Request $request): JsonResponse
{
$status = $request->route('status');
/** @var Document $document */
$document = $this->fetchesDocument->execute(['id' => $request->route('document_id')]);
$this->canApproveDocument->passes();
$document = $status === 'approve' ? $this->approvesDocument->execute($document) : $this->rejectsDocument->execute($document);
$this->updatesCompanyStatus->execute($document->owner, $status === 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED);
// $object = new NotificationObject(
// 'ID Verification ' . ( $status === 'approve' ? 'Approved' : 'Rejected' ),
// ( $status === 'approve' ? 'Dear user, congratulations that your ' : 'Dear user, we are sorry to inform you that your ' ) . ( $document->type === 'IDENTITY_CARD' ? 'IC' : 'SSM' ) . ( $status === 'approve' ? ' has been approved. Start your first order now!' : ' has been rejected due to ' . ( $request->input('rejectRemark') ?? '' ) . ', please resubmit it for further action.' ),
// $document->owner,
// $document->owner->companyModules()->first()->employees()->first(),
// $document,
// );
//
// $this->createNotificationProcessor->execute($object);
if($status === 'approve'){
$orders = $this->updatesOrdersStatus->execute($document->owner, ApprovalStatus::APPROVED);
if ($status === 'approve') {
$document = $this->approvesDocument->execute($document);
$this->updatesCompanyStatus->execute($document->owner, ApprovalStatus::APPROVED);
$this->updatesOrdersStatus->execute($document->owner, ApprovalStatus::APPROVED);
} elseif ($status === 'reject') {
$document = $this->rejectsDocument->execute($document);
$this->updatesCompanyStatus->execute($document->owner, ApprovalStatus::REJECTED);
} elseif ($status === 'pending') {
$document = $this->pendingVerificationDocument->execute($document);
$this->updatesCompanyStatus->execute($document->owner, ApprovalStatus::PENDING_VERIFICATION);
}
// $object = new NotificationObject(
// 'ID Verification ' . ( $status === 'approve' ? 'Approved' : 'Rejected' ),
// ( $status === 'approve' ? 'Dear user, congratulations that your ' : 'Dear user, we are sorry to inform you that your ' ) . ( $document->type === 'IDENTITY_CARD' ? 'IC' : 'SSM' ) . ( $status === 'approve' ? ' has been approved. Start your first order now!' : ' has been rejected due to ' . ( $request->input('rejectRemark') ?? '' ) . ', please resubmit it for further action.' ),
// $document->owner,
// $document->owner->companyModules()->first()->employees()->first(),
// $document,
// );
// $this->createNotificationProcessor->execute($object);
return $this->resourceResponse(new DocumentResource($document));
}
}
}
@@ -0,0 +1,74 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Contacts\DataTransferObjects\ContactObject;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Contacts\Services\CreatesContact;
use App\Http\Resources\ContactResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Contacts\Processors\CreateContactProcessor;
use App\Http\Resources\CompanyResource;
class CreateCompanyContactNumberLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Created Company Contact Number',
'message' => 'You have successfully created the Company Contact Number'
];
}
/** @var FetchesCompany */
private $fetchesCompany;
/** @var CreatesContact */
private $createsContact;
/** @var CreateContactProcessor */
private $createContactProcessor;
/**
* UpdateCompanyControllersLogic constructor.
* @param FetchesCompany $fetchesCompany
* @param CreatesContact $createsContact
* @param CreateContactProcessor $createContactProcessor
*/
public function __construct(FetchesCompany $fetchesCompany, CreatesContact $createsContact, CreateContactProcessor $createContactProcessor)
{
$this->fetchesCompany = $fetchesCompany;
$this->createsContact = $createsContact;
$this->createContactProcessor = $createContactProcessor;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$company = $this->fetchesCompany->execute(['id' => $request->input('companyId')]);
$contact = new ContactObject(
$company->reference,
$request->input('contactNumber'),
$company->email,
$company->wechat_id
);
$this->createContactProcessor->execute($contact, $company);
return $this->resourceResponse(new CompanyResource($company));
}
}
@@ -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,67 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Contacts\DataTransferObjects\ContactObject;
use App\Classes\Modules\Contacts\Services\FetchesContact;
use App\Classes\Modules\Contacts\Services\UpdatesContact;
use App\Http\Resources\ContactResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyContactNumberLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Updated Company Contact Number',
'message' => 'You have successfully updated the Company Contact Number'
];
}
/** @var FetchesContact */
private $fetchesContact;
/** @var UpdatesContact */
private $updatesContact;
/**
* UpdateCompanyControllersLogic constructor.
* @param FetchesContact $fetchesContact
* @param UpdatesContact $updatesContact
*/
public function __construct(FetchesContact $fetchesContact, UpdatesContact $updatesContact)
{
$this->fetchesContact = $fetchesContact;
$this->updatesContact = $updatesContact;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$query = $this->fetchesContact->execute(['id' => $request->input('id')]);
$contact = new ContactObject(
$query->reference,
$request->input('contactNumber'),
$query->email,
$query->wechat_id
);
$this->updatesContact->execute($query, $contact);
return $this->resourceResponse(new ContactResource($query));
}
}
@@ -0,0 +1,153 @@
<?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\Addresses\Standards\Rules\CanCreateAddress;
use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceInfo;
use App\Classes\Modules\Companies\Standards\Rules\CanUpdateCompany;
use App\Classes\Modules\Companies\DataTransferObjects\CompanyObject;
use App\Classes\Modules\Companies\DataTransferObjects\UpdateCompanyDetailsDTO;
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;
/**
* 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
*
*/
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
)
{
$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;
}
/**
* @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);
}
return $this->resourceResponse(new CompanyResource($company));
}
}
@@ -0,0 +1,109 @@
<?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);
//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);
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Classes\Modules\Documents\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Document;
use Carbon\Carbon;
class PendingVerificationDocument extends AbstractUpdateRecord
{
/**
* @param Document $model
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Document $model)
{
$model->status = ApprovalStatus::PENDING_VERIFICATION;
$model->approver = Auth()->user()->id;
$model->approval_date = Carbon::now();
return $this->handler($model);
}
}
@@ -0,0 +1,86 @@
<?php
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 Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ExportsAllCustomersInfoForLarkSystem implements FromQuery, WithMapping, WithHeadings, ShouldAutoSize
{
use Exportable;
protected $deduplicateMarking;
protected $request;
public function __construct(Request $request, $deduplicateMarking = true)
{
$this->deduplicateMarking = $deduplicateMarking;
$this->request = $request;
}
public function headings(): array
{
return [
'Marking',
'Name',
'Phone Number',
'Email',
'Registration Date',
'Last Order Date',
'Debtor Code',
'Credit Term Customer',
'Custom Segments',
];
}
public function query()
{
$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($connection): array
{
$company = optional(optional($connection)->invitee)->company;
$companyModule = optional($company)->companyModules->first();
$employee = optional($companyModule)->employees->first();
$contact = optional($company)->contacts->first();
$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,
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,
];
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\Exports\Services;
use App\Classes\Modules\Exports\Sheets\ContainersSheet;
use App\Classes\Modules\Exports\Sheets\PackingListsSheet;
use Carbon\Carbon;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;;
@@ -11,6 +12,14 @@ class ExportsParcel implements WithMultipleSheets
{
use Exportable;
protected $startDate;
protected $endDate;
public function __construct($startDate = null, $endDate = null) {
$this->startDate = $startDate;
$this->endDate = $endDate;
}
/**
* @return array
@@ -19,10 +28,10 @@ class ExportsParcel implements WithMultipleSheets
{
$sheets = [];
$sheets[] = new ContainersSheet();
$sheets[] = new PackingListsSheet();
$sheets[] = new ContainersSheet($this->startDate, $this->endDate);
$sheets[] = new PackingListsSheet($this->startDate, $this->endDate);
return $sheets;
}
}
}
@@ -143,8 +143,10 @@ class ExportsPaymentTransactions implements FromQuery, WithHeadings, WithHeading
// Prepare each row based on the transaction detail
$rows[] = [
$firstItem ? '<<New>>' : '',
$transaction->created_at->format('m/d/Y H:m'),
$transaction->transactions()->where('type', TransactionType::PAYMENT)->first()->updated_at->format('m/d/Y H:m'),
// $transaction->created_at->format('m/d/Y H:m'),
$transaction->created_at->format('m/d/Y'),
// $transaction->transactions()->where('type', TransactionType::PAYMENT)->first()->updated_at->format('m/d/Y H:m'),
$transaction->transactions()->where('type', TransactionType::PAYMENT)->first()->updated_at->format('m/d/Y'),
$company->debtor,
$order->reference,
$order->reference,
@@ -169,7 +171,8 @@ class ExportsPaymentTransactions implements FromQuery, WithHeadings, WithHeading
return [
'<<New>>',
$transaction->transactions()->where('type', TransactionType::PAYMENT)->first()->updated_at->format('m/d/Y H:m'),
// $transaction->transactions()->where('type', TransactionType::PAYMENT)->first()->updated_at->format('m/d/Y H:m'),
$transaction->transactions()->where('type', TransactionType::PAYMENT)->first()->updated_at->format('m/d/Y'),
$company->debtor,
$order->reference,
$order->reference,
@@ -188,7 +191,8 @@ class ExportsPaymentTransactions implements FromQuery, WithHeadings, WithHeading
];
return [
'<<New>>',
$transaction->updated_at->format('m/d/Y H:m'),
// $transaction->updated_at->format('m/d/Y H:m'),
$transaction->updated_at->format('m/d/Y'),
$company->debtor,
$container->reference,
'500-0000',
@@ -0,0 +1,78 @@
<?php
namespace App\Classes\Modules\Exports\Services;
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\Support\Facades\Log;
class ExportsSegmentCustomers implements WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize, FromQuery
{
use Exportable;
private $filters;
protected $customerMarking;
protected $segment;
public function __construct() {}
public function setParameters($customerMarking, $segment)
{
$this->customerMarking = $customerMarking;
$this->segment = $segment;
$this->filters = [
"company_segments_in" => [$this->segment],
];
if ($this->customerMarking != 0) {
$this->filters['marking_in'] = [$this->customerMarking];
}
}
public function headings(): array
{
return [
'Company Name',
'Company Marking',
'Is Credit Term Customers',
'Auto Release',
'Latest Order Creation Date',
];
}
public function query()
{
return (new ApplyFiltersToQuery())->execute(Company::query(), $this->filters);
}
public function map($list): array
{
$companyModule = $list->companyModules()->first();
$marking = $companyModule->getMarking();
$isCreditTermCustomer = false;
$segments = $companyModule->connections()->first()->segments()->pluck('name')->toArray();
$isCreditTermCustomer = in_array('Credit Term Customer', $segments);
$autoRelease = in_array('Auto Release', $segments);
$lastestOrder = $companyModule->orders()->orderBy('id', 'desc')->first();
return [
$list->name,
$marking,
$isCreditTermCustomer ? 'TRUE' : 'FALSE',
$autoRelease ? 'TRUE' : 'FALSE',
$lastestOrder ? $lastestOrder->created_at : '',
];
}
}
@@ -23,9 +23,16 @@ use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class ContainersSheet implements WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize, FromQuery, WithTitle
{
use Exportable;
protected $startDate;
protected $endDate;
public function __construct($startDate = null, $endDate = null) {
$this->startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(3);
$this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now();
}
public function headings(): array
{
return [
@@ -47,7 +54,7 @@ class ContainersSheet implements WithHeadings, WithHeadingRow, WithMapping, Shou
public function query()
{
return Container::query()
->whereBetween('created_at', [Carbon::now()->subMonths(3), Carbon::now()]); //Limit, 'expensive' query
->whereBetween('created_at', [$this->startDate, $this->endDate]); //Limit, 'expensive' query
}
/**
@@ -30,6 +30,14 @@ class PackingListsSheet implements WithHeadings, WithHeadingRow, WithMapping, Sh
use Exportable;
protected $startDate;
protected $endDate;
public function __construct($startDate = null, $endDate = null) {
$this->startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(3);
$this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now();
}
public function headings(): array
{
return [
@@ -55,7 +63,7 @@ class PackingListsSheet implements WithHeadings, WithHeadingRow, WithMapping, Sh
{
$packingLists = PackingList::where('status', '=', 2)
->whereIn('type', [PackingListType::WAREHOUSE_RECEIVE_LIST, PackingListType::SHIPPING_PACKING_LIST])
->whereBetween('created_at', [Carbon::now()->subMonths(3), Carbon::now()]) //Limit, 'expensive' query
->whereBetween('created_at', [$this->startDate, $this->endDate]) //Limit, 'expensive' query
->get();
return $packingLists->filter(function ($packingList) {
@@ -0,0 +1,49 @@
<?php
namespace App\Classes\Modules\OpenAI\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class CreatesChatGPTResponse
{
/**
* @param string $userPrompt
* @return null|object
* @throws MalformedRequestException
*/
public function execute(string $userPrompt) {
try {
$data = [
'model' => 'gpt-4-turbo', //gpt-4-turbo, gpt-4o-mini
'messages' => [
[
'role' => 'user',
'content' => $userPrompt
]
]
];
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . config('openai.api_key')
])->post(config('openai.base_url') . '/v1/chat/completions', $data);
if ($response->successful()) {
$data = $response->json();
return $data;
} else {
Log::info('CreatesChatGPTResponse: ' . $response);
return null;
}
}
catch (\Illuminate\Http\Client\ConnectionException $exception) {
$error = 'Failed to connect to ChatGPT API';
throw new ConnectionErrorException($error, $exception->getMessage(), $userPrompt, $exception->getTraceAsString());
}
catch (\Exception $exception) {
throw new MalformedRequestException('Unable to get correct response from ChatGPT API: ' . $exception->getMessage());
}
}
}
@@ -0,0 +1,84 @@
<?php
namespace App\Classes\Modules\Orders\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Orders\Services\ChecksIfOrderNumberExists;
use App\Classes\Modules\Orders\Services\RestoresOrder;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Http\Resources\OrderResource;
use App\Models\Order;
use App\Models\SupplierTaxRebate;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class CreateSupplierTaxRebateLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification(): array
{
return [
'title' => 'Create Supplier Tax Refund',
'message' => 'You have successfully created a Supplier Tax Refund'
];
}
/** @var RestoresOrder */
private $restoresOrder;
/** @var FetchesOrder */
private $fetchesOrder;
/** @var ChecksIfOrderNumberExists */
private $checkIfOrderNumberExists;
/**
* CancelOrderLogic constructor.
* @param RestoresOrder $restoresOrder
* @param FetchesOrder $fetchesOrder
*/
public function __construct(RestoresOrder $restoresOrder, FetchesOrder $fetchesOrder, ChecksIfOrderNumberExists $checkIfOrderNumberExists)
{
$this->restoresOrder = $restoresOrder;
$this->fetchesOrder = $fetchesOrder;
$this->checkIfOrderNumberExists = $checkIfOrderNumberExists;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request): JsonResponse
{
/** @var Order $order */
$order = $this->fetchesOrder->execute(['id' => $request->route('id')]);
$taxRebate = SupplierTaxRebate::create([
'order_id' => $order->id,
'supplier_name' => $request->input('supplier_name'),
'supplier_contact_number' => $request->input('supplier_contact_number'),
'reference_number' => $this->generateUniqueReferenceNumber(),
]);
return $this->resourceResponse(new OrderResource($order));
}
public function generateUniqueReferenceNumber(?string $prefix = '', ?int $length = 9): string
{
// regenerate new reference number until a new unique reference is found
do {
$reference = $prefix . rand((int)('1' . str_repeat('0', $length - 2) . '1'), (int) str_repeat('9', $length));
} while (
SupplierTaxRebate::where('reference_number', $reference)->exists() || $this->checkIfOrderNumberExists->execute($reference)
);
return $reference;
}
}
@@ -0,0 +1,41 @@
<?php
namespace App\Classes\Modules\Orders\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Models\SupplierTaxRebate;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class DeleteSupplierTaxRebateLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification(): array
{
return [
'title' => 'Delete Supplier Tax Refund',
'message' => 'You have successfully deleted a Supplier Tax Refund'
];
}
/**
* DeleteSupplierTaxRebateLogic constructor.
*/
public function __construct() {}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request): JsonResponse
{
SupplierTaxRebate::find($request->route('id'))->delete();
return $this->response([]);
}
}
@@ -10,6 +10,10 @@ use App\Http\Resources\OrderPackagesBaseResource;
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
*/
class FetchOrderPackagesLogic extends AbstractControllerLogic
{
@@ -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 FetchOrderPackagesV2Logic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Order Packages',
'message' => 'You have successfully retrieved an order packages'
];
}
/** @var CanFetchOrder */
private $canFetchOrder;
/** @var FetchesOrder */
private $fetchesOrder;
/**
* FetchOrderPackagesV2Logic 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));
}
}
@@ -0,0 +1,84 @@
<?php
namespace App\Classes\Modules\Orders\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Orders\Services\ListsOrderTracking;
use App\Http\Resources\OrderTrackingResource;
use App\Models\Order;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
use Illuminate\Contracts\Encryption\DecryptException;
use App\Classes\Modules\Orders\Standards\Rules\CanListTrackings;
class ListOrderTrackingLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Order Tracking',
'message' => 'You have successfully retrieved order tracking info'
];
}
/** @var ListsOrderTracking */
private $listsOrderTracking;
/** @var CanListTrackings */
private $canListTrackings;
/**
* ListOrderTrackingLogic constructor.
* @param CanListTrackings $canListTrackings
* @param ListsOrderTracking $listsOrderTracking
*/
public function __construct(CanListTrackings $canListTrackings, ListsOrderTracking $listsOrderTracking)
{
$this->canListTrackings = $canListTrackings;
$this->listsOrderTracking = $listsOrderTracking;
}
public function logic(Request $request) : JsonResponse
{
$query = null;
$filters = json_decode($request->input('filters'), true);
$trackingNo = $filters['tracking_no'];
try {
$trackingNo = Crypt::decryptString($trackingNo);
$trackingNo = str_replace('_01', '', $trackingNo);
} catch (DecryptException $e) {
Log::info('Decryption failed, string might already be decrypted or invalid.');
$this->canListTrackings->passes();
// if(!in_array(Auth()->user()->type, [RoleTypes::SHADOW_ADMIN, RoleTypes::SUPER_ADMIN])){
// abort(404);
// }
}
if (preg_match('/^\d{9}$/', $trackingNo)) {
$order = Order::where('reference', $trackingNo)->first();
if($order){
$packingList = $order->packingLists()->first();
$trackingNo = $packingList->reference;
Artisan::call('process-yd-by-traking-no-data-command', [
'trackingNo' => $trackingNo
]);
$query = $this->listsOrderTracking->execute(array_merge($this->listsOrderTracking->deserializeFilters($request->input('filters')), ['tracking_no' => $trackingNo]));
}
}
else{
Artisan::call('process-yd-by-traking-no-data-command', [
'trackingNo' => $trackingNo
]);
$query = $this->listsOrderTracking->execute(array_merge($this->listsOrderTracking->deserializeFilters($request->input('filters')), ['tracking_no' => $trackingNo]));
}
return $this->collectionResponse(OrderTrackingResource::collection($query));
}
}
@@ -69,10 +69,8 @@ class UpdateDoFromYDPortalProcessor
'cellphone' => $phone,
'postcode' => $address->postcode,
'streetAddress' => $address->street_one . ' ' . $address->street_two . ' '. $address->district->name.' '. $address->post_code.' '.$address->state->name.' '.$address->country->name.' '.$address->postcode.' || '.$remark
]);
]
);
} catch (\Exception $exception){
log::debug($exception);
throw new InternalServerErrorException('failed to approve address due to an error related to YD portal');
@@ -0,0 +1,31 @@
<?php
namespace App\Classes\Modules\Orders\Services;
use Illuminate\Database\Eloquent\Builder;
use App\Classes\General\Eloquent\AbstractListRecord;
use App\Models\YDOrderTracking;
class ListsOrderTracking extends AbstractListRecord
{
/** @var YDOrderTracking */
private $repository;
/**
* ListsOrderTracking constructor.
* @param YDOrderTracking $repository
*/
public function __construct(YDOrderTracking $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,47 @@
<?php
namespace App\Classes\Modules\Orders\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\ValueObjects\Constants\RoleTypes;
class CanListTrackings extends AbstractRule
{
/**
* @return bool
*/
protected function authorized($object): bool
{
if(Auth()->user()){
$roleToCheck = Auth()->user()->type;
if (in_array($roleToCheck, RoleTypes::ADMIN_ROLES)) {
return true;
}
else {
return false;
}
}
return false;
}
/**
* @param BookingObject $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param BookingObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -107,8 +107,17 @@ class AssignPackingListOrderLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
// $warehouse_packing_list = $this->fetchesPackingList->execute([
// 'id' => $request->route('id'),
// 'type' => PackingListType::WAREHOUSE_RECEIVE_LIST
// ]);
$packing_list = $this->fetchesPackingList->execute([
'id' => $request->route('id'),
]);
$warehouse_packing_list = $this->fetchesPackingList->execute([
'id' => $request->route('id'),
'reference' => $packing_list->reference,
'type' => PackingListType::WAREHOUSE_RECEIVE_LIST
]);
@@ -9,6 +9,8 @@ use App\Classes\Modules\PackingLists\Standards\Rules\Packages\CanCreatePackage;
use App\Classes\ValueObjects\Constants\WarehouseReferences;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\Segment;
use Illuminate\Support\Facades\Log;
class CreatePackageProcessor
{
@@ -53,6 +55,14 @@ class CreatePackageProcessor
if($replica->owner->owner instanceof Order){
$modificationValue = in_array( $replica->owner->owner->companyModule->id, WarehouseReferences::REPLICA_WHITE_LIST) ? 0 : 1;
// if customer in segment 'No Extra Centimeter Charged'
$segmentId = Segment::where('name', 'No Extra Centimeter Charged')->first()->id;
$companySegments = $replica->owner->owner->companyModule->connections()->first()->segments->pluck('id')->toArray();
if (in_array($segmentId, $companySegments)) {
$modificationValue = 0;
Log::info('No Extra Centimeter Charged segment working');
}
}
$packageObject = new PackageObject($object->getType(), $object->getDescription(), $object->getWidth() + $modificationValue, $object->getHeight() + $modificationValue, $object->getLength() + $modificationValue, $object->getWeight(), $object->getQuantity(), $object->getStatus());
@@ -0,0 +1,328 @@
<?php
namespace App\Classes\Modules\PackingLists\Processors\V2;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Orders\Services\FetchesDataFromYDPortal;
use App\Classes\Modules\OpenAI\Services\CreatesChatGPTResponse;
use App\Models\PackingList;
use App\Models\YDOrderTracking;
use Carbon\Carbon;
use DateTime;
use Illuminate\Support\Facades\Log;
class FetchByTrakingNoYdPortalV2Processor
{
/** @var FetchesDataFromYDPortal */
private $fetchesDataFRomYDPortal;
/** @var CreatesChatGPTResponse */
private $createsChatGPTResponse;
/**
* @param FetchesDataFromYDPortal $fetchesDataFRomYDPortal
* @param CreatesChatGPTResponse $createsChatGPTResponse
*/
public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal, CreatesChatGPTResponse $createsChatGPTResponse)
{
$this->fetchesDataFRomYDPortal = $fetchesDataFRomYDPortal;
$this->createsChatGPTResponse = $createsChatGPTResponse;
}
/**
* @param PackingList $packingList
* @return void
* @throws MalformedRequestException
*/
public function execute(PackingList $packingList)
{
Log::info('FetchByTrakingNoYdPortalV2Processor starts with packingList id ' . $packingList->id);
// return;
$reference = $packingList->reference;
Log::info('reference ' . $reference);
$oneHourAgo = Carbon::now()->subHour();
$check1 = YDOrderTracking::where('tracking_no', $reference)
->orderBy('updated_at', 'desc')
->first();
if ($check1 && $check1->updated_at >= $oneHourAgo) {
Log::info('FetchByTrakingNoYdPortalV2Processor SKIPPED: Record updated within the last hour');
Log::info('---');
return;
}
$this->processTrackingNo($reference);
Log::info('FetchByTrakingNoYdPortalV2Processor ends with packingList id ' . $packingList->id);
Log::info('---');
}
/**
* @param string $reference
* @return void
* @throws MalformedRequestException
*/
public function processTrackingNo(string $reference){
$time_start = microtime(true);
$check2 = YDOrderTracking::where('tracking_no', $reference)
->where('tracking', '第三方提货')
->first();
// if ($check2) {
// Log::info('FetchByTrakingNoYdPortalV2Processor SKIPPED: 第三方提货');
// Log::info('---');
// return;
// }
$trackingRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/ApiTracking.ashx', 'GET', [
'trakingno' => $reference
]);
$rows = $this->fetchesDataFRomYDPortal->getResponseBody($trackingRequest);
$this->processData(json_encode($rows), $reference);
$time_end = microtime(true);
$execution_time = ($time_end - $time_start)/60;
Log::info('FetchByTrakingNoYdPortalV2Processor ends with reference ' . $reference . ' => Total Execution Time: '.$execution_time.' Mins.');
}
private function processData($jsonData, $reference)
{
$data = json_decode($jsonData, true);
if ($data['res'] == 1 && isset($data['data'])) {
Log::info('package_id: '.$data['data'][0]['package_id']);
foreach (array_reverse($data['data']) as $item) {
$existingRecord = YDOrderTracking::where('order_tracking_id', $item['Id'])
->where('tracking_no', $reference)
->first();
// Log::info('tracking: '.$item['tracking']);
// Log::info('remark: '.$item['remark']);
if (!$existingRecord) {
$etdEta = $this->parseEtdEta($item['remark'], $item['tracking'], $item['trackingtime']);
$isTrackingTranslatedPreviouly = $this->checkIfTranslationAlreadyExist(!empty($item['tracking']) ? $item['tracking'] : "");
$isRemarkTranslatedPreviouly = $this->checkIfTranslationAlreadyExist(!empty($item['remark']) ? $item['remark'] : "");
YDOrderTracking::create([
'order_tracking_id' => $item['Id'],
'tracking_no' => $reference,
'package_id' => $item['package_id'],
'tracking' => $item['tracking'] ?? null,
'tracking_english' => $isTrackingTranslatedPreviouly ? $isTrackingTranslatedPreviouly : $this->translateTracking($item['tracking']),
'tracking_time' => $item['trackingtime'] ?? null,
'add_time' => $item['addtime'] ?? null,
'remark' => $item['remark'] ?? null,
'remark_english' => $item['remark'] ? ($isRemarkTranslatedPreviouly ? $isRemarkTranslatedPreviouly : $this->translateTracking($item['remark'])) : null,
'etd' => $etdEta['etd'],
'eta' => $etdEta['eta']
]);
Log::info('FetchByTrakingNoYdPortalV2Processor RECORD CREATED');
}
else{
$isUpdated = false;
if($item['tracking']){
$isTranslatedPreviouly = $this->checkIfTranslationAlreadyExist(!empty($item['tracking']) ? $item['tracking'] : "");
$result = $isTranslatedPreviouly;
if (!$isTranslatedPreviouly){
$result = $this->translateTracking($item['tracking']);
}
if ($result && $existingRecord->tracking_english !== $result) {
$existingRecord->update([
'tracking_english' => $result
]);
$isUpdated = true;
}
}
if($item['remark']) {
$isTranslatedPreviouly = $this->checkIfTranslationAlreadyExist(!empty($item['remark']) ? $item['remark'] : "");
$result = $isTranslatedPreviouly;
if (!$isTranslatedPreviouly){
$result = $this->translateTracking($item['remark']);
}
if ($result && $existingRecord->remark_english !== $result) {
$existingRecord->update([
'remark_english' => $result
]);
$isUpdated = true;
}
}
if($isUpdated){
Log::info('FetchByTrakingNoYdPortalV2Processor RECORD UPDATED');
}
else{
Log::info('FetchByTrakingNoYdPortalV2Processor RECORD EXIST');
}
}
}
}
}
public function parseEtdEta($remark, $tracking, $trackingtime)
{
$etd = null;
$eta = null;
$etaString = '';
$etdString = '';
if($remark && $tracking !== '第三方提货'){
if (preg_match('/(?:预计|延)(\d+\.\d+)(?:号)?开/', $remark, $matches)) {
$etdString = $matches[1];
}
if (preg_match('/(?:预计)?(\d+\.\d+)(?:号)?到港/', $remark, $matches)) {
$etaString = $matches[1];
}
Log::info('remark: '.$remark);
$currentYear = Carbon::now()->year;
$trackingDate = Carbon::parse($trackingtime);
$trackingYear = $trackingDate->year;
if($remark && preg_match('/\b\d{1,2}[-\/.]\d{1,2}\b/', $remark) && $eta === null && $etd === null){
$existingRecord = YDOrderTracking::where('remark', $remark)->where(function ($query) {
$query->whereNotNull('eta')
->orWhereNotNull('etd');
})
->first();
if($existingRecord){
Log::info('FetchByTrakingNoYdPortalV2Processor SAVER');
return [
'etd' => $existingRecord->etd,
'eta' => $existingRecord->eta,
];
}
$userPrompt = "Show me the answer in json string without escape, e.g. {'ETA': '', 'ETD': ''}. ".$remark." What is the ETA and ETD?";
Log::info('prompt: '.$userPrompt);
$result = $this->createsChatGPTResponse->execute($userPrompt);
Log::info('result (json_encoded): '.json_encode($result));
$content = $result['choices'][0]['message']['content'] ?? null;
Log::info('content (json_encoded):'. json_encode($content));
if ($content) {
$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']);
$etaString = $parsedContent['ETA'];
$etdString = $parsedContent['ETD'];
$dateParts = explode('-', $etaString);
if (count($dateParts) === 3) {
$etaString = $dateParts[1] . '-' . $dateParts[2];
}
$dateParts = explode('-', $etdString);
if (count($dateParts) === 3) {
$etdString = $dateParts[1] . '-' . $dateParts[2];
}
}
}
}
if (!empty($etaString) && preg_match('/\b\d{1,2}[-\/.]\d{1,2}\b/', $etaString)) {
$etaString = str_replace(['.', '-', '/'], '/', $etaString);
$etaParts = explode('/', $etaString);
$etaMonth = intval($etaParts[0]);
$etaDay = intval($etaParts[1]);
$etaDate = DateTime::createFromFormat("Y/m/d", "$currentYear/$etaString");
if($trackingYear < $currentYear){
$etaDate = DateTime::createFromFormat("Y/m/d", ($trackingYear) . "/$etaString");
}
else{
$etaYear = $currentYear;
if ($etaMonth <= 2 && $trackingDate->month == 12) {
$etaYear = $trackingDate->year + 1;
}
$etaDate = Carbon::createFromDate($etaYear, $etaMonth, $etaDay);
}
if($etaDate){
$eta = $etaDate->format('Y-m-d');
}
Log::info('ETA: '.$eta);
Log::info('ETD: '.$etd);
}
if (!empty($etdString) && preg_match('/\b\d{1,2}[-\/.]\d{1,2}\b/', $etdString)) {
$etdString = str_replace(['.', '-', '/'], '/', $etdString);
$etdParts = explode('/', $etdString);
$etdMonth = intval($etdParts[0]);
$etdDay = intval($etdParts[1]);
$etdDate = DateTime::createFromFormat("Y/m/d", "$currentYear/$etdString");
if($trackingYear < $currentYear){
$etdDate = DateTime::createFromFormat("Y/m/d", ($trackingYear) . "/$etdString");
}
else{
$etdYear = $currentYear;
if ($etdMonth <= 1 && $trackingDate->month == 12) {
$etdYear = $trackingDate->year + 1;
}
$etdDate = Carbon::createFromDate($etdYear, $etdMonth, $etdDay);
}
if($etdDate){
$etd = $etdDate->format('Y-m-d');
}
Log::info('ETD: '.$etd);
Log::info('ETA: '.$eta);
}
}
return [
'etd' => $etd ? date('Y-m-d', strtotime($etd)) : null,
'eta' => $eta ? date('Y-m-d', strtotime($eta)) : null,
];
}
private function checkIfTranslationAlreadyExist($textToTranslate)
{
$returnText = "";
Log::info('textToTranslate: '.$textToTranslate);
if(!$textToTranslate) return $returnText;
$translationFound = YDOrderTracking::where('tracking', $textToTranslate)->whereNotNull('tracking_english')->first();
if(!$translationFound){
$translationFound = YDOrderTracking::where('remark', $textToTranslate)->whereNotNull('remark_english')->first();
if($translationFound){
$returnText = $translationFound->remark_english;
}
}
else{
$returnText = $translationFound->tracking_english;
}
Log::info('FOUND EXISTING TRANSLATION: '.$returnText);
return $returnText;
}
private function translateTracking($textToTranslate)
{
$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);
Log::info('result (json_encoded): '.json_encode($result));
$content = $result['choices'][0]['message']['content'] ?? null;
Log::info('content (json_encoded):'. json_encode($content));
$parsedContent = json_decode(str_replace("'", '"', $content), true);
if($parsedContent && $parsedContent['english']){
Log::info('Translated Text: ' . $parsedContent['english']);
return $parsedContent['english'];
}
else{
return null;
}
}
}
@@ -105,10 +105,12 @@ class FetchContainersFromYdPortalV2Processor
$loadingDate = null;
$etd = null;
$eta = null;
$reference = $packingList->reference;
$trackingRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/ApiTracking.ashx', 'GET', [
'trakingno' => $packingList->reference
'trakingno' => $reference
]);
Log::info('YDContainer reference ' . $reference);
$rows = $this->fetchesDataFRomYDPortal->getResponseBody($trackingRequest);
@@ -117,22 +119,24 @@ class FetchContainersFromYdPortalV2Processor
}
foreach (array_reverse($rows->data) as $trackingRow) {
Log::info('YDContainer trackingRow ' . json_encode($trackingRow));
if (strpos($trackingRow->tracking, '货物装柜完成。') !== false) {
$tracking = explode(':', $trackingRow->tracking);
$containerReference = explode('预计到港时间', $tracking[1])[0];
$loadingDate = Carbon::parse($trackingRow->trackingtime);
$etd = Carbon::parse($tracking[2])->subDays(5);
$eta = Carbon::parse($tracking[2]);
$eta = Carbon::parse($tracking[2]);
}
}
if($containerReference) {
try {
Log::info('YDContainer try ' . json_encode($containerReference));
$container = $this->fetchesContainer->execute(['reference' => $containerReference]);
$container->packingLists()->detach($packingList);
$container->packingLists()->attach($packingList);
} catch (ResourceNotFoundException $exception){
Log::info('YDContainer catch ' . json_encode($containerReference));
if(!($packingList->owner instanceof Order)) return;
$originWarehouse = $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_WAREHOUSE)->first()->appointee;
@@ -61,11 +61,13 @@ class FetchContainersUpdatesFromYdPortalV2Processor
$time_start = microtime(true);
$packingList = $container->packingLists()->first();
$reference = $packingList->reference;
$trackingRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/ApiTracking.ashx', 'GET', [
'trakingno' => $packingList->reference
'trakingno' => $reference
]);
Log::info('YDContainerUpdates reference ' . $reference);
$rows = $this->fetchesDataFRomYDPortal->getResponseBody($trackingRequest);
if(!$rows->data){
@@ -78,6 +80,8 @@ class FetchContainersUpdatesFromYdPortalV2Processor
$checkShipArrivalDate = null;
foreach (array_reverse($rows->data) as $trackingRow) {
Log::info('YDContainerUpdates trackingRow ' . json_encode($trackingRow));
$rescheduleETD = strpos($trackingRow->remark, '开') || strpos($trackingRow->remark, '到港');
$rescheduleETA = strpos($trackingRow->remark, '到港');
@@ -150,9 +154,10 @@ class FetchContainersUpdatesFromYdPortalV2Processor
if($delayDate){
$transport = $container->transports()->first();
Log::info('YDContainerUpdates delayDate ' . json_encode($transport));
if(!$transport->schedules()->whereDate('eta', '>=', $delayDate)->first()) {
$etd = $transport->schedules()->where('status', '=', ApprovalStatus::APPROVED)->first()->etd;
Log::info('YDContainerUpdates etd ' . json_encode($etd));
$transport->schedules()->update(['status' => ApprovalStatus::EXPIRED]);
$this->createsSchedule->execute($transport, new ScheduleObject($etd, $delayDate, ApprovalStatus::APPROVED));
foreach ($container->packingLists as $packingList){
@@ -159,17 +159,21 @@ class FetchPackingListsFromYdPortalV2Processor
try{
$packingList = $this->fetchesPackingList->execute(['reference' => $row->expressno, 'type' => PackingListType::SHIPPING_PACKING_LIST]);
Log::info('Fetch SHIPPING_PACKING_LIST id: ' . $packingList->id);
$packingList->packages()->delete();
$replica = $packingList->packingLists()->where('type', PackingListType::SHIPPING_PACKING_LIST_REPLICA)->first();
if($replica) $replica->packages()->delete();
$warehouseReceiveList = $this->fetchesPackingList->execute(['reference' => $row->expressno, 'type' => PackingListType::WAREHOUSE_RECEIVE_LIST]);
Log::info('Fetch WAREHOUSE_RECEIVE_LIST id: ' . $warehouseReceiveList->id);
$warehouseReceiveList->packages()->delete();
$replica = $warehouseReceiveList->packingLists()->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST_REPLICA)->first();
if($replica) $replica->packages()->delete();
} catch (ResourceNotFoundException $exception) {
Log::info('SHIPPING_PACKING_LIST/WAREHOUSE_RECEIVE_LIST NOT FOUND');
if (!$allow_contract) {
$appointee_id = 2307;
@@ -181,6 +185,7 @@ class FetchPackingListsFromYdPortalV2Processor
/** @var PackingList $warehouseReceiveList */
$warehouseReceiveList = $this->createPackingListProcessor->execute($warehouseReceiveObject, $order);
Log::info('Create WAREHOUSE_RECEIVE_LIST id: ' . $warehouseReceiveList->id);
$transportObject = new TransportObject(TransportType::LAND, null, $row->kuaidilist, Carbon::parse($receiveDate), Carbon::parse($receiveDate), $allow_contract ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED);
$transport = $this->createsTransport->execute($transportObject, $warehouseReceiveList);
@@ -209,6 +214,7 @@ class FetchPackingListsFromYdPortalV2Processor
/** @var PackingList $packingList */
$packingList = $this->createPackingListProcessor->execute($packingListObject, $order);
Log::info('Create SHIPPING_PACKING_LIST id: ' . $packingList->id);
if ($allow_contract) {
foreach ($contractObligations as $obligation) {
@@ -0,0 +1,229 @@
<?php
namespace App\Classes\Modules\PackingLists\Processors\V3;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Schedules\DataTransferObjects\ScheduleObject;
use App\Classes\Modules\Schedules\Services\CreatesSchedule;
use App\Classes\Modules\Unity\Services\UpdatesContractObligation;
use App\Classes\Modules\PerfexCRM\Processors\PackingListToPerfexCRMProcessor;
use App\Classes\Notifications\ShipmentRescheduleEmail;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\OrderRoleTypes;
use App\Classes\ValueObjects\Constants\PerfexCRMTasksYDStages;
use App\Models\Container;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\YDOrderTracking;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class FetchContainersUpdatesYdPortalV3Processor
{
/** @var UpdatesContractObligation */
private $updatesContractObligations;
/** @var CreatesSchedule */
private $createsSchedule;
/** @var PackingListToPerfexCRMProcessor */
private $packingListToPerfexCRMProcessor;
/**
* @param UpdatesContractObligation $updatesContractObligations
* @param CreatesSchedule $createsSchedule
* @param PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor
*/
public function __construct(UpdatesContractObligation $updatesContractObligations, CreatesSchedule $createsSchedule, PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor)
{
$this->updatesContractObligations = $updatesContractObligations;
$this->createsSchedule = $createsSchedule;
$this->packingListToPerfexCRMProcessor = $packingListToPerfexCRMProcessor;
}
/**
* @param Container $container
* @return void
* @throws MalformedRequestException
*/
public function execute(Container $container)
{
Log::info('FetchContainersUpdatesFromYdPortalV2Processor starts with container id ' . $container->id . ' created_at ' . $container->created_at);
// return;
$time_start = microtime(true);
$packingList = $container->packingLists()->first();
$reference = $packingList->reference;
Log::info('FetchContainersUpdatesFromYdPortalV2Processor starts with packingList id ' . $packingList->id . ' created_at ' . $packingList->created_at);
Log::info('FetchContainersUpdatesFromYdPortalV2Processor starts with reference ' . $reference);
if (!$container->created_at->greaterThanOrEqualTo(Carbon::now()->subYear())) {
return;
}
$trackingRows = YDOrderTracking::where('tracking_no', $reference)->get();
Log::info('YDContainerUpdates trackingRows ' . (count($trackingRows) > 0 ? json_encode($trackingRows) : 'NOT FOUND'));
Log::info('YDContainerUpdates order ' . json_encode($packingList->owner));
$unstuffingDate = null;
$delayETADate = null;
$delayETDDate = null;
$checkShipSailDate = null;
$checkShipArrivalDate = null;
foreach ($trackingRows as $trackingRow) {
if($trackingRow->eta){
if(!$delayETADate){
$delayETADate = Carbon::parse($trackingRow->eta);
}
if(Carbon::parse($trackingRow->eta) > $delayETADate){
$delayETADate = Carbon::parse($trackingRow->eta);
}
}
if($trackingRow->etd){
if(!$delayETDDate){
$delayETDDate = Carbon::parse($trackingRow->etd);
}
if(Carbon::parse($trackingRow->etd) > $delayETDDate){
$delayETDDate = Carbon::parse($trackingRow->etd);
}
}
}
if ($delayETDDate && $delayETADate && $delayETDDate->isAfter($delayETADate)){
$delayETADate = null;
}
foreach ($trackingRows as $trackingRow) {
if ($trackingRow->tracking === '到港') {
Log::info('YDContainerUpdates - 到港 delayDate ' . $delayETADate);
Log::info('YDContainerUpdates - 到港 $trackingRow->tracking_time ' . $trackingRow->tracking_time);
$delayETADate = Carbon::parse($trackingRow->tracking_time);
$checkShipArrivalDate = Carbon::parse($trackingRow->tracking_time);
}
if ($trackingRow->tracking === '已开船') {
Log::info('YDContainerUpdates - 已开船 delayDate ' . $delayETADate);
if(!$delayETADate){
Log::info('YDContainerUpdates - 已开船 $trackingRow->tracking_time add 5 days ' . $trackingRow->tracking_time);
$delayETADate = Carbon::parse($trackingRow->tracking_time)->addDays('5');
}
$checkShipSailDate = Carbon::parse($trackingRow->tracking_time);
}
if ($trackingRow->tracking === '货物已进目的港仓库' || $trackingRow->tracking === '第三方提货') {
Log::info('YDContainerUpdates - 货物已进目的港仓库 delayDate ' . $delayETADate);
$unstuffingDate = Carbon::parse($trackingRow->tracking_time);
}
}
if($checkShipSailDate){
//check if ship has sailed
if($checkShipSailDate->isPast()){
foreach ($container->packingLists as $packingList){
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::SHIP_SAILED);
}
}
}
}
if($checkShipArrivalDate){
//check if ship has arrived at destination
if($checkShipArrivalDate->isPast()){
foreach ($container->packingLists as $packingList){
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::SHIP_ARRIVED);
}
}
}
}
if($delayETADate){
Log::info('YDContainerUpdates delayETADate ' . $delayETADate);
$transport = $container->transports()->first();
Log::info('YDContainerUpdates transport ' . json_encode($transport));
if(!$transport->schedules()->whereDate('eta', '>=', $delayETADate)->first()) { //If no record
$etd = $transport->schedules()->where('status', '=', ApprovalStatus::APPROVED)->first()->etd;
if($delayETDDate > Carbon::parse($etd)){
$etd = $delayETDDate;
Log::info('YDContainerUpdates new etd');
}
Log::info('YDContainerUpdates etd ' . json_encode($etd));
$transport->schedules()->update(['status' => ApprovalStatus::EXPIRED]);
$this->createsSchedule->execute($transport, new ScheduleObject($etd, $delayETADate, ApprovalStatus::APPROVED));
foreach ($container->packingLists as $packingList){
if(!($packingList->owner instanceof Order)) continue;
$user = $packingList->owner->companyModule->employees()->first();
if(app()->environment(['production'])) {
$user->notify(new ShipmentRescheduleEmail($user, $packingList));
}
}
}
else{
Log::info('YDContainerUpdates NO DELAY (ETA)');
}
}
else if($delayETDDate){
//Runs when delayETDDate is available but NOT delayETADate
Log::info('YDContainerUpdates delayETDDate ' . $delayETDDate);
$transport = $container->transports()->first();
Log::info('YDContainerUpdates transport ' . json_encode($transport));
if(!$transport->schedules()->whereDate('etd', '>=', $delayETDDate)->first()) { //If no record
$eta = $delayETDDate->copy()->addDays(5);
$transport->schedules()->update(['status' => ApprovalStatus::EXPIRED]);
$this->createsSchedule->execute($transport, new ScheduleObject($delayETDDate, $eta, ApprovalStatus::APPROVED));
foreach ($container->packingLists as $packingList){
if(!($packingList->owner instanceof Order)) continue;
$user = $packingList->owner->companyModule->employees()->first();
if(app()->environment(['production'])) {
$user->notify(new ShipmentRescheduleEmail($user, $packingList));
}
}
}
else{
Log::info('YDContainerUpdates NO DELAY (ETD)');
}
}
if($unstuffingDate){
$container->update(['status' => ApprovalStatus::COMPLETED]);
$container->transports()->first()->update(['drop_date' => $unstuffingDate, 'status' => ApprovalStatus::COMPLETED]);
/** @var PackingList $packingList */
foreach($container->packingLists as $packingList){
if($packingList->status === ApprovalStatus::PENDING_VERIFICATION){
$packingList->status = ApprovalStatus::APPROVED;
$packingList->save();
}
if(!($packingList->owner instanceof Order)) continue;
$signature = $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::SUPERVISOR)->first()->appointee->entity_sigiture;
foreach($packingList->steps()->where('reference', '!=', 'DELIVERY')->get() as $step){
if(app()->environment(['production'])) {
$this->updatesContractObligations->execute($signature, $step->obligation_hash_id);
}
$step->update(['status' => ApprovalStatus::COMPLETED]);
}
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::UNSTUFFING);
}
}
}
$time_end = microtime(true);
$execution_time = ($time_end - $time_start)/60;
Log::info('FetchContainersUpdatesFromYdPortalV2Processor ends with container id ' . $container->id . ' => Total Execution Time: '.$execution_time.' Mins.');
Log::info('---');
}
}
@@ -0,0 +1,149 @@
<?php
namespace App\Classes\Modules\PackingLists\Processors\V3;
use App\Classes\Exceptions\AccessForbiddenException;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\RequestValidationException;
use App\Classes\Exceptions\ResourceNotFoundException;
use App\Classes\Modules\PackingLists\Processors\CreateContainerProcessor;
use App\Classes\Modules\PackingLists\DataTransferObjects\ContainerObject;
use App\Classes\Modules\PackingLists\Services\Containers\FetchesContainer;
use App\Classes\Modules\Schedules\DataTransferObjects\ScheduleObject;
use App\Classes\Modules\Schedules\Services\CreatesSchedule;
use App\Classes\Modules\Transports\DataTransferObjects\TransportObject;
use App\Classes\Modules\Transports\Services\CreatesTransport;
use App\Classes\Modules\PerfexCRM\Processors\PackingListToPerfexCRMProcessor;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\ContainerTypes;
use App\Classes\ValueObjects\Constants\OrderRoleTypes;
use App\Classes\ValueObjects\Constants\TransportType;
use App\Classes\ValueObjects\Constants\PerfexCRMTasksYDStages;
use App\Models\Container;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\Transport;
use App\Models\YDOrderTracking;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class FetchContainersYdPortalV3Processor
{
/** @var CreatesTransport */
private $createsTransport;
/** @var CreatesSchedule */
private $createsSchedule;
/** @var FetchesContainer */
private $fetchesContainer;
/** @var CreateContainerProcessor */
private $createContainerProcessor;
/** @var PackingListToPerfexCRMProcessor */
private $packingListToPerfexCRMProcessor;
/**
* @param CreatesTransport $createsTransport
* @param CreatesSchedule $createsSchedule
* @param FetchesContainer $fetchesContainer
* @param CreateContainerProcessor $createContainerProcessor
* @param PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor
*/
public function __construct(CreatesTransport $createsTransport, CreatesSchedule $createsSchedule, FetchesContainer $fetchesContainer, CreateContainerProcessor $createContainerProcessor, PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor)
{
$this->createsTransport = $createsTransport;
$this->createsSchedule = $createsSchedule;
$this->fetchesContainer = $fetchesContainer;
$this->createContainerProcessor = $createContainerProcessor;
$this->packingListToPerfexCRMProcessor = $packingListToPerfexCRMProcessor;
}
/**
* @param PackingList $packingList
* @return void
* @throws MalformedRequestException
* @throws AccessForbiddenException
* @throws RequestValidationException
*/
public function execute(PackingList $packingList)
{
Log::info('FetchContainersFromYdPortalV2Processor starts with packingList id '. $packingList->id);
// return;
$time_start = microtime(true);
$containerReference = null;
$loadingDate = null;
$etd = null;
$eta = null;
$reference = $packingList->reference;
Log::info('YDContainer reference ' . $reference);
$trackingRows = YDOrderTracking::where('tracking_no', $reference)->get();
Log::info('YDContainer trackingRows ' . json_encode($trackingRows));
foreach ($trackingRows as $trackingRow) {
if (strpos($trackingRow->tracking, '货物装柜完成。') !== false) {
$tracking = explode(':', $trackingRow->tracking);
$containerReference = explode('预计到港时间', $tracking[1])[0];
$loadingDate = Carbon::parse($trackingRow->tracking_time);
$etd = Carbon::parse($tracking[2])->subDays(5);
$eta = Carbon::parse($tracking[2]);
}
}
Log::info('YDContainer containerReference ' . json_encode($containerReference));
if($containerReference) {
try {
Log::info('YDContainer try');
$container = $this->fetchesContainer->execute(['reference' => $containerReference]);
$container->packingLists()->detach($packingList);
$container->packingLists()->attach($packingList);
} catch (ResourceNotFoundException $exception){
Log::info('YDContainer catch');
if(!($packingList->owner instanceof Order)) return;
$originWarehouse = $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_WAREHOUSE)->first()->appointee;
$containerObject = new ContainerObject($containerReference, '', '', ContainerTypes::FORTY_FEET_DRY_CONTAINER, $loadingDate, ApprovalStatus::PENDING_VERIFICATION);
/** @var Container $container */
$container = $this->createContainerProcessor->execute($containerObject, $originWarehouse);
$container->packingLists()->detach($packingList);
$container->packingLists()->attach($packingList);
if(config('perfexcrm.is_enabled') == 'true'){
$this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::LOAD_CONTAINER);
}
$transport = $container->transports()->first();
if(!$transport){
$transportObject = new TransportObject(TransportType::SEA, null, null, $etd, null, ApprovalStatus::APPROVED);
/** @var Transport $transport */
$transport = $this->createsTransport->execute($transportObject, $container);
$this->createsSchedule->execute($transport, new ScheduleObject($etd, $eta, ApprovalStatus::APPROVED));
}
}
Log::info('YDContainer loadingDate ' . $loadingDate);
Log::info('YDContainer etd ' . $etd);
Log::info('YDContainer eta ' . $eta);
}
$time_end = microtime(true);
$execution_time = ($time_end - $time_start)/60;
Log::info('FetchContainersFromYdPortalV2Processor ends with packingList id '. $packingList->id . ' => Total Execution Time: '.$execution_time.' Mins.');
Log::info('---');
}
}
@@ -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;
}
}
@@ -13,8 +13,11 @@ use App\Classes\Modules\Transactions\Processors\CreatePaymentTransactionProcesso
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Document;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ApprovePaymentTransactionLogic extends AbstractControllerLogic
{
@@ -71,12 +74,21 @@ class ApprovePaymentTransactionLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$status = $request->route('status');
Log::info("ApprovePaymentTransactionLogic ".$status);
$transaction = $this->fetchesTransaction->execute(['id' => $request->route('transaction_id')]);
$status === 'approve' ? $this->approvesDocument->execute($transaction->documents()->where('status', ApprovalStatus::PENDING_VERIFICATION)->first()) : $this->rejectsDocument->execute($transaction->documents()->where('status', ApprovalStatus::PENDING_VERIFICATION)->first());
$document = $transaction->documents()
->where('status', ApprovalStatus::PENDING_VERIFICATION)
->first();
if($status === 'approve') {
$this->approvesDocument->execute($document);
}
else {
$this->rejectsDocument->execute($document);
}
$this->updatesTransactionStatus->execute($transaction, $status === 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED);
@@ -22,6 +22,7 @@ use App\Models\GroupTransaction;
use App\Http\Resources\WalletTransactionResource;
use App\Models\Wallet;
use App\Classes\Modules\Transactions\Processors\ReleaseGoodsToCustomerProcessor;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
class CreateGroupsLogic extends AbstractControllerLogic
@@ -60,6 +61,8 @@ class CreateGroupsLogic extends AbstractControllerLogic
/** @var ReleaseGoodsToCustomerProcessor */
private $releaseGoodsToCustomerProcessor;
/** @var CheckStorageInvoiceTransactionProcessor */
private $checkStorageInvoiceTransactionProcessor;
public function __construct(
FetchesTransaction $fetchesTransaction,
@@ -68,7 +71,8 @@ class CreateGroupsLogic extends AbstractControllerLogic
CreateWalletTopUpTransactionProcessor $createWalletTopUpTransactionProcessor,
CreatePaymentTransactionProcessor $createPaymentTransactionProcessor,
CreatesGroup $createsGroup,
ReleaseGoodsToCustomerProcessor $releaseGoodsToCustomerProcessor
ReleaseGoodsToCustomerProcessor $releaseGoodsToCustomerProcessor,
CheckStorageInvoiceTransactionProcessor $checkStorageInvoiceTransactionProcessor
)
{
$this->fetchesTransaction = $fetchesTransaction;
@@ -78,6 +82,7 @@ class CreateGroupsLogic extends AbstractControllerLogic
$this->createPaymentTransactionProcessor = $createPaymentTransactionProcessor;
$this->createsGroup = $createsGroup;
$this->releaseGoodsToCustomerProcessor = $releaseGoodsToCustomerProcessor;
$this->checkStorageInvoiceTransactionProcessor = $checkStorageInvoiceTransactionProcessor;
}
public function logic(Request $request) : JsonResponse
@@ -87,6 +92,52 @@ class CreateGroupsLogic extends AbstractControllerLogic
// todo-new: check why is this not working
// $invoices = $this->fetchesTransaction->execute(['id_in' => $invoice_ids]);
$invoices = Transaction::whereIn('id', $invoice_ids)->get();
$typeOneInvoices = $invoices->filter(function ($invoice) {
return $invoice->type == 1;
});
// Check amount to be paid by customer 1
$amount = $request->input('amount');
if($typeOneInvoices)
{
foreach ($typeOneInvoices as $invoice) {
$storages = $this->checkStorageInvoiceTransactionProcessor->executeShippingTransaction($invoice);
$invoice['storages'] = $storages;
}
$totalAmount = $typeOneInvoices->reduce(function ($total, $transaction) {
$topLevelAmount = $transaction->amount ?? 0;
$storagesAmount = collect($transaction['storages'] ?? [])->reduce(function ($sum, $storage) {
$storageInvoiceAmount = $storage['storageInvoice']['amount'] ?? 0;
return $sum + $storageInvoiceAmount;
}, 0);
return $total + $topLevelAmount + $storagesAmount;
}, 0);
$diff = abs($amount - $totalAmount);
if($diff > 0.01){
$response = ['message' => 'Some information has been updated, please reload the page to proceed. [ref: 001]'];
return $this->response(['data' => $response]);
}
}
// Check amount to be paid by customer 2
$totalAmount = 0;
$proceed = false;
foreach ($invoices as $invoice) {
$totalAmount += $invoice->amount;
}
if(abs($totalAmount - $amount ) > 0.01){
$proceed = true;
}
if($proceed){
// $response = ['message' => 'Total: '.$totalAmount. ', submitted amount: '.$request->input('amount').', proceed: true'];
$response = ['message' => 'Some information has been updated, please reload the page to proceed. [ref: 002]'];
return $this->response(['data' => $response]);
}
$isInvoicesApprove = $this->checkIfInvoicesAreApprove($invoices);
if(!$isInvoicesApprove){
$response = ['message' => 'One of the transactions might be suspended; please check if there are any disputes in progress.'];
@@ -95,7 +146,6 @@ class CreateGroupsLogic extends AbstractControllerLogic
else{
$paymentMethodStr = $request->input('payment_method');
$paymentMethod = PaymentMethodType::PAYMENT_METHODS[$paymentMethodStr];
$amount = $request->input('amount');
$bankCode = $request->input('bank_code');
$result = $this->processInvoices($invoices, $paymentMethodStr, $amount, $bankCode);
@@ -62,7 +62,7 @@ class CreatePaymentTransactionLogic extends AbstractControllerLogic
return $this->resourceResponse(new TransactionResource($payment_transaction));
}
$response = ['message' => 'A transaction might be suspended; please check if there is any dispute in progress.'];
$response = ['message' => 'Transaction might be already completed or suspended; please check if there is any dispute in progress.'];
return $this->response(['data' => $response]);
}
@@ -0,0 +1,55 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Models\Transaction;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use App\Http\Resources\TransactionVerifyResource;
class VerifyTransactionsLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Verify Transactions',
'message' => 'You have successfully verified submitted transactions'
];
}
/** @var CheckStorageInvoiceTransactionProcessor */
private $checkStorageInvoiceTransactionProcessor;
public function __construct(
CheckStorageInvoiceTransactionProcessor $checkStorageInvoiceTransactionProcessor
)
{
$this->checkStorageInvoiceTransactionProcessor = $checkStorageInvoiceTransactionProcessor;
}
public function logic(Request $request) : JsonResponse
{
$invoice_ids = json_decode($request->route('transaction_ids'));
$invoices = Transaction::whereIn('id', $invoice_ids)->get();
$result = $this->processInvoices($invoices);
return $this->collectionResponse(TransactionVerifyResource::collection($result));
}
private function processInvoices($invoices){
foreach ($invoices as $invoice) {
$storages = $this->checkStorageInvoiceTransactionProcessor->executeShippingTransaction($invoice);
$invoice['storages'] = $storages;
}
return $invoices;
}
}
@@ -128,33 +128,58 @@ class CheckStorageInvoiceTransactionProcessor
$packingLists = $order->destinationWarehousePackages;
foreach ($packingLists as $packingList){
$arrivalDateAtChinaWarehouse = $this->getArrivalDateAtChinaWarehoue($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();
$newResults = $this->getResults($packingList, $order, $is_credit_term);
$results = array_merge($results, $newResults);
}
/** @var Transaction $invoice_transaction */
foreach ($transactions as $invoice_transaction){
$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;
}
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;
}
private function getResults($packingList, $order, $is_credit_term){
$results = [];
$arrivalDateAtChinaWarehouse = $this->getArrivalDateAtChinaWarehoue($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){
$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 getArrivalDateAtChinaWarehoue($packingList){
if($packingList->type === PackingListType::SHIPPING_PACKING_LIST){
$receive_packing_list = PackingList::where('reference', $packingList->reference)->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST)->first();
@@ -88,7 +88,7 @@ class CreatePaymentTransactionProcessor
public function execute(Transaction $invoice, $payment_method, $bank_code, $run = true)
{
$amount = $invoice->amount;
Log::info($invoice->owner);
Log::info('CreatePaymentTransactionProcessor: '.$invoice->owner);
$company_module = $invoice->owner->owner->companyModule()->first();
$approvalStatus = ApprovalStatus::PENDING_SUBMISSION;
$billNumber = $this->generatesTransactionBillNumber->execute('PYMT-');
@@ -61,6 +61,8 @@ class ReleaseGoodsToCustomerProcessor
$invoiceTransactions = $packingList->transactions()->where('status', ApprovalStatus::APPROVED)->whereIn('type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])->get();
}
LogHelper::channel('storage_invoices')->info('invoiceTransactions: '. json_encode($invoiceTransactions));
//Part 1: Process each single invoice type and get the total of all invoices (STORAGE + SHIPPING)
foreach($invoiceTransactions as $invoiceTransaction){
$totalInvoiceAmountPaid = $invoiceTransaction->transactions->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount');
@@ -69,7 +71,6 @@ class ReleaseGoodsToCustomerProcessor
Log::channel('storage_invoices')->info('ReleaseGoodsToCustomerProcessor updatesTransactionStatus');
$this->updatesTransactionStatus->execute($invoice, ApprovalStatus::COMPLETED);
//cief todo: remove the following if block
if($invoice->type === TransactionType::STORAGE_INVOICE){
Log::channel('storage_invoices')->info('ReleaseGoodsToCustomerProcessor createStorageInvoiceDocTransactionProcessor');
$this->createStorageInvoiceDocTransactionProcessor->execute($packingList);
@@ -10,4 +10,6 @@ final class AddressType {
public const PICK_UP = 3;
public const E_INVOICE = 4;
}
@@ -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;
}
}
@@ -60,14 +60,14 @@ class OneTimeTransactionFixBillplzFailedCallback extends Command
$this->outputArray = [];
$start = new Carbon();
//Transaction fix with this one time fix command: 15205, 16803, 17310
//Transaction fix with this one time fix command: 15205, 16803, 17310, 20960
//This transaction, 16803 has approve payment but not its owner, shipping invoice
$transaction = Transaction::whereIn('id', [17310])->first();
$this->info(Carbon::now() . ' : One time fix failled callback from billplz for transaction with id 17310 cron started.');
$transaction = Transaction::whereIn('id', [20960])->first();
$this->info(Carbon::now() . ' : One time fix failled callback from billplz for transaction with id 20960 cron started.');
if($transaction && $transaction->id == 17310){
if($transaction && $transaction->id == 20960){
$this->info(Carbon::now() . ' : 17310.');
$this->info(Carbon::now() . ' : 20960.');
$status = ApprovalStatus::APPROVED;
// $this->callbackBillplzProcessor->execute($transaction, $status);
$this->callbackBillplzDataPatchProcessor->execute($transaction, $status);
@@ -76,6 +76,6 @@ class OneTimeTransactionFixBillplzFailedCallback extends Command
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
$this->info(Carbon::now() . ' : One time fix failled callback from billplz for transaction with id 17310 cron ended. ElapsedTime: ' . $elapsedTime);
$this->info(Carbon::now() . ' : One time fix failled callback from billplz for transaction with id 20960 cron ended. ElapsedTime: ' . $elapsedTime);
}
}
@@ -0,0 +1,47 @@
<?php
namespace App\Console\Commands\V2;
use App\Classes\Jobs\Commands\V2\FixPaymentApprovalTimedOutErrorV2CommandJob;
use Illuminate\Console\Command;
class FixPaymentApprovalTimedOutErrorV2Command extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'fix-payment-approval-timed-out-error-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fix payment approval timed out error';
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()
{
FixPaymentApprovalTimedOutErrorV2CommandJob::dispatch();
}
}
@@ -0,0 +1,77 @@
<?php
namespace App\Console\Commands\V2;
use App\Classes\Jobs\Commands\V2\YD\FetchPackingListsFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchContainersFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchContainersUpdatesFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchDeliveryUpdatesFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchOrderListsFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V3\YD\FetchContainersYdPortalV3CommandJob;
use App\Classes\Jobs\Commands\V3\YD\FetchContainersUpdatesYdPortalV3CommandJob;
use App\Models\PackingList;
use App\Models\Container;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Log;
class OneTimeProcessYDPortalDataV2Command extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'one-time-process-yd-portal-data-command {start_date?} {end_date?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'One time process data from YD Portal for the given date range';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$jobs = [];
$jobs1 = $this->fetchPackingListsFromYdPortalV2CommandJobs();
foreach ($jobs1 as $index => $job) {
dispatch($job)->delay(now()->addSeconds($index * 2));
}
}
private function fetchPackingListsFromYdPortalV2CommandJobs(){
$jobs = [];
// $startDate1 = Carbon::create(2025, 1, 15, 0, 0, 0);
// $endDate1 = Carbon::create(2025, 1, 16, 23, 59, 59);
// $startDate2 = Carbon::create(2025, 2, 18, 0, 0, 0);
// $endDate2 = Carbon::create(2025, 2, 19, 23, 59, 59);
// $jobs[] = new FetchPackingListsFromYdPortalV2CommandJob($startDate1, $endDate1);
// $jobs[] = new FetchPackingListsFromYdPortalV2CommandJob($startDate2, $endDate2);
$startDate = Carbon::create(2025, 4, 17);
$endDate = Carbon::create(2025, 4, 18);
$jobs[] = new FetchPackingListsFromYdPortalV2CommandJob($startDate, $endDate);
Log::info('Dispatched FetchPackingListsFromYdPortalV2CommandJob (one-time-process)');
return $jobs;
}
}
@@ -0,0 +1,81 @@
<?php
namespace App\Console\Commands\V2;
use App\Classes\Jobs\Commands\V2\YD\FetchTrakingInfoYDByPackingListV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchTrakingInfoYDByTrackingNoV2CommandJob;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Models\PackingList;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class ProcessYDByTrakingNoDataV2Command extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'process-yd-by-traking-no-data-command {trackingNo?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Process data from YD Portal by traking no';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$trackingNo = $this->argument('trackingNo');
if ($trackingNo) {
$lockKey = "process_yd_tracking_no:{$trackingNo}";
$lock = Cache::lock($lockKey, 300);
if (!$lock->get()) {
Log::info("Tracking No {$trackingNo} is already being processed. Try again later.");
return;
}
dispatch(new FetchTrakingInfoYDByTrackingNoV2CommandJob($trackingNo));
Log::info("Job dispatched for tracking number: {$trackingNo}");
}
else {
$jobs = $this->fetchByTrakingNoYdPortalV2CommandJob();
foreach ($jobs as $index => $job) {
$delayInSeconds = intdiv($index, 2);
dispatch($job)->delay(now()->addSeconds($delayInSeconds));
}
}
}
private function fetchByTrakingNoYdPortalV2CommandJob(){
$jobs = [];
$maxFetchTime = Carbon::now()->subMonths(4);
$packingLists = PackingList::where('type', PackingListType::SHIPPING_PACKING_LIST)->whereDate('created_at', '>=', $maxFetchTime)->get();
$count = 0;
foreach ($packingLists as $packingList) {
$jobs[] = new FetchTrakingInfoYDByPackingListV2CommandJob($packingList);
Log::info('Dispatched FetchByTrakingNoYdPortalV2CommandJob for packingList with id ' . $packingList->id . ' reference ' . $packingList->reference . ' created_at ' . $packingList->created_at);
$count++;
// Log::info('Dispatched count '. $count);
// if ($count === 50) {
// break;
// }
}
Log::info('Total FetchByTrakingNoYdPortalV2CommandJob dispatched: ' . $count);
return $jobs;
}
}
@@ -7,6 +7,8 @@ use App\Classes\Jobs\Commands\V2\YD\FetchContainersFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchContainersUpdatesFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchDeliveryUpdatesFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V2\YD\FetchOrderListsFromYdPortalV2CommandJob;
use App\Classes\Jobs\Commands\V3\YD\FetchContainersYdPortalV3CommandJob;
use App\Classes\Jobs\Commands\V3\YD\FetchContainersUpdatesYdPortalV3CommandJob;
use App\Models\PackingList;
use App\Models\Container;
@@ -42,29 +44,32 @@ class ProcessYDPortalDataV2Command extends Command
public function handle()
{
$jobs = [];
$jobs = array_merge($jobs, $this->fetchPackingListsFromYdPortalV2CommandJobs());
$jobs = array_merge($jobs, $this->fetchContainersFromYdPortalV2CommandJobs());
$jobs2 = $this->fetchContainersUpdatesFromYdPortalV2CommandJob();
$jobs3 = $this->fetchDeliveryUpdatesFromYdPortalV2CommandJobs();
$jobs1 = $this->fetchPackingListsFromYdPortalV2CommandJobs();
$jobs2 = $this->fetchContainersYdPortalV3CommandJobs();
$jobs3 = $this->fetchContainersUpdatesYdPortalV3CommandJob();
$jobs4 = $this->fetchDeliveryUpdatesFromYdPortalV2CommandJobs();
// The following job is intentionally excluded
////$jobs = array_merge($jobs, $this->fetchOrderListsFromYdPortalV2CommandJob());
////$jobs5 = array_merge($jobs, $this->fetchOrderListsFromYdPortalV2CommandJob());
// Bus::chain($jobs)->dispatch();
foreach ($jobs as $index => $job) {
foreach ($jobs1 as $index => $job) {
dispatch($job)->delay(now()->addSeconds($index * 2));
}
foreach ($jobs2 as $index => $job) {
dispatch($job)->delay(now()->addSeconds($index * 1));
dispatch($job);
}
foreach ($jobs3 as $index => $job) {
dispatch($job);
}
foreach ($jobs4 as $index => $job) {
$delayInSeconds = intdiv($index, 2);
dispatch($job)->delay(now()->addSeconds($delayInSeconds));
}
}
private function fetchPackingListsFromYdPortalV2CommandJobs(){
@@ -138,6 +143,37 @@ class ProcessYDPortalDataV2Command extends Command
return $jobs;
}
private function fetchContainersYdPortalV3CommandJobs(){
$jobs = [];
$maxFetchTime = Carbon::now()->subMonths(4);
$packingLists = PackingList::where('type', PackingListType::SHIPPING_PACKING_LIST)->whereDate('created_at', '>=', $maxFetchTime)->doesntHave('containers')->get();
$count = 0;
foreach ($packingLists as $packingList) {
$jobs[] = new FetchContainersYdPortalV3CommandJob($packingList);
Log::info('Dispatched FetchContainersYdPortalV3CommandJob for packingList with id ' . $packingList->id . ' created_at ' . $packingList->created_at);
$count++;
}
Log::info('Total fetchContainersYdPortalV3CommandJobs dispatched: ' . $count);
return $jobs;
}
private function fetchContainersUpdatesYdPortalV3CommandJob(){
$jobs = [];
$containers = Container::where('status', ApprovalStatus::PENDING_VERIFICATION)->get();
$count = 0;
foreach ($containers as $container) {
$jobs[] = new FetchContainersUpdatesYdPortalV3CommandJob($container);
Log::info('Dispatched fetchContainersUpdatesYdPortalV3CommandJob for container with id ' . $container->id);
$count++;
}
Log::info('Total fetchContainersUpdatesYdPortalV3CommandJob dispatched: ' . $count);
return $jobs;
}
private function fetchDeliveryUpdatesFromYdPortalV2CommandJobs(){
$jobs = [];
+5 -1
View File
@@ -55,8 +55,12 @@ class Kernel extends ConsoleKernel
// ->cron('0 9-18/3 * * *')
// ->withoutOverlapping();
$schedule->command('process-yd-by-traking-no-data-command')
->cron('0 8,11,14,17 * * *')
->withoutOverlapping();
$schedule->command('process-yd-portal-data-command')
->cron('0 10,14,18 * * *') // ->cron('0 9-18/3 * * *')
->cron('0 9,12,15,18 * * *') //->cron('0 9-18/3 * * *')
->withoutOverlapping();
$schedule->command('fix-packinglist-command')
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Companies;
use App\Classes\Modules\Companies\ControllersLogic\CreateCompanyContactNumberLogic;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateCompanyContactNumberController extends Controller
{
/**
* @param Request $request
* @param CreateCompanyContactNumberLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateCompanyContactNumberLogic $logic): JsonResponse
{
return $logic->execute($request);
}
}
@@ -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\UpdateCompanyContactNumberLogic;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyContactNumberController extends Controller
{
/**
* @param Request $request
* @param UpdateCompanyLogic $logic
* @return JsonResponse
*/
public function update(Request $request, UpdateCompanyContactNumberLogic $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);
}
}
@@ -13,6 +13,7 @@ use App\Classes\Modules\Exports\Services\ExportsAgingList;
use Illuminate\Support\Facades\Storage;
use App\Classes\General\AWSS3Helper;
use App\Http\Controllers\Controller;
use Carbon\Carbon;
class ExportArrivedParcelController extends Controller
{
@@ -45,7 +46,24 @@ class ExportArrivedParcelController extends Controller
}
public function summary(Request $request) {
$exportsParcelsSummary = new ExportsParcel();
$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;
if (isset($validated['startDate']) && $validated['startDate']) {
$startDate = Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay();
}
if (isset($validated['endDate']) && $validated['endDate']) {
$endDate = Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay();
}
$exportsParcelsSummary = new ExportsParcel($startDate, $endDate);
$exportFileName = 'parcel-summary.xls';
$filesystemDriver = Storage::getDefaultDriver();
if($filesystemDriver === 's3'){
@@ -10,6 +10,9 @@ use Illuminate\Support\Facades\Auth;
use Maatwebsite\Excel\Excel;
use Illuminate\Support\Facades\Storage;
use App\Classes\General\AWSS3Helper;
use App\Classes\Modules\Exports\Services\ExportsAllCustomersInfoForLarkSystem;
use App\Classes\Modules\Exports\Services\ExportsSegmentCustomers;
use App\Models\Segment;
class ExportCompanyModuleSummaryController
{
@@ -53,4 +56,46 @@ class ExportCompanyModuleSummaryController
return $response;
}
}
public function exportSegmentCustomers(Request $request)
{
$exportsSegmentCustomers = new ExportsSegmentCustomers($request);
$customer_marking = $request->route('companyMarking');
$segment = $request->route('segment');
$exportsSegmentCustomers->setParameters($customer_marking, $segment);
$segment_name = Segment::find($request->route('segment'))->name;
$segment_name = $segment_name ? strtolower(str_replace(' ', '_', $segment_name)): 'segment';
$exportFileName = $segment_name . '_customers.xls';
$filesystemDriver = Storage::getDefaultDriver();
if ($filesystemDriver === 's3') {
return response(['src' => AWSS3Helper::S3Exportable($exportFileName, $exportsSegmentCustomers)]);
} else {
$response = $exportsSegmentCustomers->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
ob_end_clean();
return $response;
}
}
public function exportAllCustomersInfoForLarkSystem(Request $request)
{
$password = $request->input('password');
if ($password !== 'all_customers_data') {
return response()->json(['error' => 'Invalid password'], 403);
}
$exportsAllCustomersInfoForLarkSystem = new ExportsAllCustomersInfoForLarkSystem($request);
$exportFileName = 'shipping_all_customers_info_for_lark_system.xls';
$filesystemDriver = Storage::getDefaultDriver();
if ($filesystemDriver === 's3') {
return response(['src' => AWSS3Helper::S3Exportable($exportFileName, $exportsAllCustomersInfoForLarkSystem)]);
} else {
$response = $exportsAllCustomersInfoForLarkSystem->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
ob_end_clean();
return $response;
}
}
}
@@ -60,11 +60,19 @@ class ExportCustomersToExcelController
}
}
public function groupTransaction(Request $request){
public function groupTransaction(Request $request)
{
$exportsTransactions = new ExportsGroupTransactions($request);
$response = $exportsTransactions->download('group-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
ob_end_clean();
return $response;
$exportFileName = 'group-transactions.xls';
$filesystemDriver = Storage::getDefaultDriver();
if($filesystemDriver === 's3'){
return response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $exportsTransactions) ]);
}
else{
$response = $exportsTransactions->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
// ob_end_clean();
return $response;
}
}
public function totalOrders(Request $request){
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Orders;
use App\Classes\Modules\Orders\ControllersLogic\CreateSupplierTaxRebateLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateSupplierTaxRebateController
{
/**
* @param Request $request
* @param RestoreOrderLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateSupplierTaxRebateLogic $logic): JsonResponse
{
return $logic->execute($request);
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Orders;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Orders\ControllersLogic\DeleteSupplierTaxRebateLogic;
use Illuminate\Support\Facades\Log;
class DeleteSupplierTaxRebateController
{
/**
* @param Request $request
* @param DeleteSupplierTaxRebateLogic $logic
* @return JsonResponse
*/
public function delete(Request $request, DeleteSupplierTaxRebateLogic $logic): JsonResponse
{
return $logic->execute($request);
}
}
@@ -0,0 +1,99 @@
<?php
namespace App\Http\Controllers\Orders;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\OrderRoleTypes;
use App\Classes\ValueObjects\Constants\WarehouseReferences;
use App\Models\Order;
use Illuminate\Http\Request;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\General\AWSS3Helper;
use App\Models\SupplierTaxRebate;
use Illuminate\Support\Facades\Storage;
class DownloadTaxRebateQrPdfController
{
public function download(Request $request){
$order = Order::find($request->route('id'));
$deliveryAddress = $order->addresses()->where('status', ApprovalStatus::APPROVED)->first();
$warehouse= $order->orderRoles()->where('role_id', OrderRoleTypes::ORIGIN_WAREHOUSE)->first()->appointee;
$warehouseAddress = $warehouse->addresses()->first();
$warehouseContacts = $warehouse->contacts;
$warehousePrefix = '';
$deliveryPrefix = '';
$customerMarking = '';
$remark = $warehouse->remarks()->first();
if($warehouse->reference === WarehouseReferences::VT_GUANG_ZHOU || $warehouse->reference === WarehouseReferences::VT_YIWU) {
$customerMarking = $order->companyModule->connections()->first()->invitee_reference.'/';
if(strtolower($deliveryAddress->state->name) === 'sabah' || strtolower($deliveryAddress->state->name) === 'labuan') {
$deliveryPrefix = 'SB/';
}
if(strtolower($deliveryAddress->state->name) === 'sarawak') {
$deliveryPrefix = 'SRW/';
}
}
if($warehouse->reference === WarehouseReferences::YD_YIWU){
$warehousePrefix = 'YW/';
}
if(in_array($warehouse->reference,[WarehouseReferences::YD_GUANG_ZHOU, WarehouseReferences::YD_GUANG_ZHOU_2, WarehouseReferences::YD_FS_EAST_MALAYSIA, WarehouseReferences::YD_FS_WEST_MALAYSIA])){
$warehousePrefix = 'YD/';
if(strtolower($deliveryAddress->state->name) === 'sabah' || strtolower($deliveryAddress->state->name) === 'labuan' || in_array(strtolower($deliveryAddress->district->name), ['limbang', 'lawas'])) {
$warehousePrefix = 'KK/';
}
if(strtolower($deliveryAddress->state->name) === 'sarawak' && !in_array(strtolower($deliveryAddress->district->name), ['limbang', 'lawas'])) {
$warehousePrefix = 'KU/';
}
if(strtolower($deliveryAddress->state->name) === 'johor') {
$warehousePrefix = 'NX/';
}
}
// tax rebate data
$tax_rebate_refeerence = $request->query('tax_rebate_refeerence');
$supplierTaxRebate = SupplierTaxRebate::where('reference_number', $tax_rebate_refeerence)->first();
if (!$supplierTaxRebate) {
// If not found, throw an error
abort(404, 'Supplier Tax Refund not found');
}
$data = [
'order' => $order,
'marking' => $warehousePrefix.$deliveryPrefix.'CIEF/'.$customerMarking,
'delivery_address' => $deliveryAddress,
'warehouse_address' => $warehouseAddress,
'warehouse_contacts' => $warehouseContacts,
'remark' => $remark ? $remark->content : '',
'supplierTaxRebate' => $supplierTaxRebate
];
$pdf = LaravelMpdf::loadView('pdfs.tax_rebate_qr', $data, [], [
'title' => 'CIEF_ORDER_NO_'.$order->reference,
'format' => 'A4-L',
'orientation' => 'L',
'margin_top' => '40px',
]);
$exportFileName = 'CIEF_ORDER_NO_'.$order->reference.'.pdf';
$filesystemDriver = Storage::getDefaultDriver();
if($filesystemDriver === 's3'){
$pdfContent = $pdf->output();
return response([ 'src' => AWSS3Helper::S3PDF($exportFileName, $pdfContent) ]);
}
else{
return $pdf->stream($exportFileName);
}
}
}
@@ -6,6 +6,10 @@ use App\Classes\Modules\Orders\ControllersLogic\FetchOrderPackagesLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
/**
* @deprecated This class is deprecated and should not be used.
* Use `FetchOrderPackagesV2Controller` instead or write a new one based on FetchOrderPackagesV2Controller
*/
class FetchOrderPackagesController
{
/**
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Orders;
use App\Classes\Modules\Orders\ControllersLogic\FetchOrderPackagesV2Logic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchOrderPackagesV2Controller
{
/**
* @param Request $request
* @param FetchOrderLogic $logic
* @return JsonResponse
*/
public function fetch(Request $request, FetchOrderPackagesV2Logic $logic): JsonResponse
{
return $logic->execute($request);
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Orders;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Orders\ControllersLogic\ListOrderTrackingLogic;
class ListOrderTrackingController
{
/**
* @param Request $request
* @param ListOrderTrackingLogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListOrderTrackingLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\Rules;
use App\Classes\Modules\Rules\ControllersLogic\CheckEInvoiceRuleLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CheckRuleController
{
/**
* @param Request $request
* @param CheckEInvoiceRuleLogic $logic
* @return JsonResponse
*/
public function checkEInvoiceRule(Request $request, CheckEInvoiceRuleLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -5,11 +5,11 @@ namespace App\Http\Controllers\Transactions;
use App\Classes\Modules\Transactions\ControllersLogic\ApprovePaymentTransactionLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ApprovePaymentTransactionController
{
public function approve(Request $request, ApprovePaymentTransactionLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
}
@@ -12,7 +12,7 @@ class CreateGroupsController
{
/**
* @param Request $request
* @param CreatePurchaseOrderTransactionLogic $logic
* @param CreateGroupsLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateGroupsLogic $logic) : JsonResponse {
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Transactions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\VerifyTransactionsLogic;
class VerifyTransactionsController
{
/**
* @param Request $request
* @param VerifyTransactionsLogic $logic
* @return JsonResponse
*/
public function verify(Request $request, VerifyTransactionsLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
+1
View File
@@ -75,5 +75,6 @@ class Kernel extends HttpKernel
'storage.invoice.check.bytransactions' => \App\Http\Middleware\CheckForStorageInvoiceByTransactions::class,
'storage.invoice.check.bygroup' => \App\Http\Middleware\CheckForStorageInvoiceByGroup::class,
'storage.invoice.check.bypackinglists' => \App\Http\Middleware\CheckForStorageInvoiceByPackingLists::class,
'admin' => \App\Http\Middleware\EnsureUserIsAdmin::class, //cief todo: 90 - maintenance
];
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Http\Middleware;
use App\Classes\ValueObjects\Constants\RoleTypes;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Tymon\JWTAuth\Facades\JWTAuth;
class EnsureUserIsAdmin
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$maintenanceTitle = env('MAINTENANCE_MESSAGE_TITLE', null);
if (!empty($maintenanceTitle)) {
$user = JWTAuth::parseToken()->authenticate();
if(!in_array($user->type, RoleTypes::ADMIN_ROLES)){
return response()->view('errors.503', [], 503);
}
}
return $next($request);
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class AddressEInvoiceResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'street_one' => $this->street_one,
'street_two' => $this->street_two,
'district' => $this->district,
'state' => $this->state,
'post_code' => (string) $this->postcode,
'country' => $this->country,
'billing' => (int) $this->billing
];
}
}

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