324 Commits

Author SHA1 Message Date
f32ea8028c Merge pull request 'added profile logo in visitor' (#206) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #206
2026-05-26 10:27:04 +00:00
dhanabalan
2dd3b35eb5 added profile logo in visitor
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-26 15:56:46 +05:30
a65b9fcc62 Merge pull request 'added default avatar ui image in visitor' (#205) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #205
2026-05-26 10:01:23 +00:00
dhanabalan
4129a7a251 added default avatar ui image in visitor
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-26 15:31:10 +05:30
4ffb200fc3 Merge pull request 'ranjith-dev' (#204) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #204
2026-05-26 09:58:38 +00:00
dhanabalan
d6aea93d00 removed default image url in visitor
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-26 15:28:23 +05:30
dhanabalan
fb91bea7c4 changed logic in visito entry
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
2026-05-26 15:27:25 +05:30
53a85b3b39 Merge pull request 'Changed logic in create visitor entry' (#203) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #203
2026-05-26 09:44:29 +00:00
dhanabalan
f970d6eb0f Changed logic in create visitor entry
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-26 15:14:14 +05:30
cba147226a Merge pull request 'Changed image path of visitor photos' (#202) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #202
2026-05-26 09:03:21 +00:00
dhanabalan
b567f3ee02 Changed image path of visitor photos
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-26 14:33:06 +05:30
47ddc4f1f1 Merge pull request 'changed logic in create visitor' (#201) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #201
2026-05-26 08:51:31 +00:00
dhanabalan
e7fa446fc3 changed logic in create visitor
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-26 14:21:09 +05:30
e49e71e101 Merge pull request 'Added photo column in table section' (#200) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #200
2026-05-25 11:51:13 +00:00
dhanabalan
f399808249 Added photo column in table section
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-25 17:20:32 +05:30
882dd021a0 Merge pull request 'Added logic to show captured image' (#199) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #199
2026-05-25 10:26:01 +00:00
dhanabalan
575d3675cf Added logic to show captured image
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-25 15:55:45 +05:30
7ea85b6351 Merge pull request 'changed logic in livewire' (#198) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #198
2026-05-25 10:18:53 +00:00
dhanabalan
7435928fcf changed logic in livewire
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-25 15:48:42 +05:30
9b4b78301d Merge pull request 'ranjith-dev' (#197) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #197
2026-05-25 10:17:00 +00:00
dhanabalan
d6acded332 Added capture photo logic in livewire
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-25 15:46:47 +05:30
dhanabalan
915a766aa0 Added visitor entry resource pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
2026-05-25 15:45:42 +05:30
dhanabalan
e123dd65b5 Added visitor entry model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
2026-05-25 15:44:35 +05:30
dhanabalan
f420f05179 Added visitor entry migration file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
2026-05-25 15:44:01 +05:30
8b31e29986 Merge pull request 'ranjith-dev' (#196) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #196
2026-05-25 10:11:42 +00:00
dhanabalan
84f165beea Added employee master importer and exporter pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-25 15:41:18 +05:30
dhanabalan
8d397f11e1 Added employee master resource pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
2026-05-25 15:40:48 +05:30
dhanabalan
19feaba66a Added employee master model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
2026-05-25 15:39:47 +05:30
dhanabalan
912b793e8d Added employee master migration file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
2026-05-25 15:39:23 +05:30
45c68daf20 Merge pull request 'modified logic in chat bot' (#195) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #195
2026-05-20 06:50:58 +00:00
dhanabalan
ccd922b5bb modified logic in chat bot
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-20 12:20:22 +05:30
711218521c Merge pull request 'Added chat bot pages' (#194) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #194
2026-05-20 05:52:21 +00:00
dhanabalan
203d09712b Added chat bot pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-05-20 11:21:57 +05:30
c3c77fa737 Merge pull request 'Chnaged logic for showing qr code based on content' (#193) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #193
2026-04-27 10:55:50 +00:00
dhanabalan
d9f531fbc6 Chnaged logic for showing qr code based on content
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-04-27 16:25:32 +05:30
bac841c3fa Merge pull request 'Added PrintController and updated route for sticker PDF generation' (#192) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #192
2026-04-27 08:39:32 +00:00
dhanabalan
142094fd00 Added PrintController and updated route for sticker PDF generation
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-04-27 14:09:17 +05:30
631cfedef2 Merge pull request 'Changed logic in sticker pdf service' (#191) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #191
2026-04-27 08:38:31 +00:00
dhanabalan
ab86517fc1 Changed logic in sticker pdf service
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-04-27 14:08:17 +05:30
4aa0acb85d Merge pull request 'Changed printer logic in sticker validation' (#190) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #190
2026-04-27 05:37:14 +00:00
dhanabalan
f66839131e Changed printer logic in sticker validation
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-04-27 11:06:38 +05:30
root
91cad60e02 Revert "Merge pull request 'Added category in item resource page' (#189) from ranjith-dev into master"
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
This reverts commit e0cfe7ccea, reversing
changes made to 3c8bcb2e9e.
2026-03-21 09:14:24 +00:00
e0cfe7ccea Merge pull request 'Added category in item resource page' (#189) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #189
2026-03-21 09:08:48 +00:00
dhanabalan
7244028d02 Added category in item resource page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-03-21 14:38:27 +05:30
3c8bcb2e9e Merge pull request 'added production quantity in production plan resource page' (#188) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #188
2026-02-21 08:54:21 +00:00
dhanabalan
8104da98d4 added production quantity in production plan resource page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 2m32s
Laravel Pint / pint (pull_request) Failing after 2m41s
2026-02-21 14:23:22 +05:30
ef62ca360b Merge pull request 'Removed production quantity in prodcution plan resource page' (#187) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #187
2026-02-21 04:31:12 +00:00
dhanabalan
1d51067355 Removed production quantity in prodcution plan resource page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 22s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 28s
Laravel Larastan / larastan (pull_request) Failing after 2m36s
Laravel Pint / pint (pull_request) Failing after 3m1s
2026-02-21 10:00:47 +05:30
16d7f74115 Merge pull request 'Chnaged logic in production quantity page' (#186) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #186
2026-02-16 10:55:29 +00:00
dhanabalan
1fd2538048 Chnaged logic in production quantity page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 16:25:14 +05:30
9fe342df80 Merge pull request 'Changed logic in export of production plan' (#185) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #185
2026-02-16 09:45:02 +00:00
dhanabalan
d8fdf02417 Changed logic in export of production plan
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 15:14:46 +05:30
b421692560 Merge pull request 'Changed logic for showing data in dashboard in production quantity' (#184) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #184
2026-02-16 08:47:35 +00:00
dhanabalan
1031a972de Changed logic for showing data in dashboard in production quantity
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 14:17:22 +05:30
c17dc86d48 Merge pull request 'Changed logic in production quantity page for last scanned qr' (#183) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #183
2026-02-16 07:31:07 +00:00
dhanabalan
f5173d9861 Changed logic in production quantity page for last scanned qr
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 13:00:55 +05:30
129f9169f4 Merge pull request 'Changed logic in production quantity page' (#182) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #182
2026-02-16 06:59:14 +00:00
dhanabalan
9602be624d Changed logic in production quantity page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 12:29:02 +05:30
6532f2d075 Merge pull request 'Added line_id and line_capacity in item model file' (#181) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #181
2026-02-16 06:20:36 +00:00
dhanabalan
85c7a3e286 Added line_id and line_capacity in item model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:50:24 +05:30
fb965f3871 Merge pull request 'Added machine id column in production quantity model file' (#180) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #180
2026-02-16 06:18:43 +00:00
dhanabalan
6071c8b898 Added machine id column in production quantity model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:48:33 +05:30
e609b32954 Merge pull request 'Added block_id column in line model file' (#179) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #179
2026-02-16 06:17:14 +00:00
dhanabalan
9bf5337383 Added block_id column in line model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:47:01 +05:30
3c59e06fe7 Merge pull request 'Added columns in production plan model file' (#178) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #178
2026-02-16 06:15:06 +00:00
dhanabalan
621cf13565 Added columns in production plan model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:44:53 +05:30
aee5a8cb50 Merge pull request 'Added Block in line resource page' (#177) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #177
2026-02-16 06:11:46 +00:00
dhanabalan
6c334359b2 Added Block in line resource page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:41:34 +05:30
6e8b02e742 Merge pull request 'Changed logic in production plan resource page' (#176) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #176
2026-02-16 05:59:40 +00:00
dhanabalan
fd444a7749 Changed logic in production plan resource page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:29:25 +05:30
1988dfcc0e Merge pull request 'Changed logic against item_id in prouction plan importer' (#175) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #175
2026-02-16 05:58:24 +00:00
dhanabalan
f7a421681e Changed logic against item_id in prouction plan importer
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:28:12 +05:30
df0904e6c1 Merge pull request 'Added production plan export in production target page' (#174) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #174
2026-02-16 05:56:32 +00:00
dhanabalan
8bd64c80d4 Added production plan export in production target page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:26:20 +05:30
a2958c999c Merge pull request 'Changed logic in production quantity page' (#173) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #173
2026-02-16 05:55:30 +00:00
dhanabalan
c4177887d6 Changed logic in production quantity page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:25:15 +05:30
051616da25 Merge pull request 'Added production target screen pages and livewire pages' (#172) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #172
2026-02-16 05:46:23 +00:00
dhanabalan
09772d1984 Added production target screen pages and livewire pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:16:08 +05:30
8cf1063e2a Merge pull request 'Added Production Calendar screen page' (#171) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #171
2026-02-16 05:44:17 +00:00
dhanabalan
3376d35eaa Added Production Calendar screen page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:14:03 +05:30
b7ec4f4c1a Merge pull request 'Added leave dates column to production plan table' (#170) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #170
2026-02-16 05:39:48 +00:00
dhanabalan
8feb2fc612 Added leave dates column to production plan table
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:09:38 +05:30
f26209f3db Merge pull request 'Added working days column in production plan table' (#169) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #169
2026-02-16 05:38:38 +00:00
dhanabalan
04d472805f Added working days column in production plan table
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:08:27 +05:30
23914944ca Merge pull request 'Added machine_id foreign key in production quantities table' (#168) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #168
2026-02-16 05:37:10 +00:00
dhanabalan
f9d2e14210 Added machine_id foreign key in production quantities table
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:06:40 +05:30
e4b951ff77 Merge pull request 'Added line_id and line_capacity column in items table' (#167) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #167
2026-02-16 05:35:26 +00:00
dhanabalan
13bef51af5 Added line_id and line_capacity column in items table
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:05:13 +05:30
2c8efe351b Merge pull request 'Added block id foreign key in lines table' (#166) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #166
2026-02-16 05:33:30 +00:00
dhanabalan
1711ce5646 Added block id foreign key in lines table
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 11:03:11 +05:30
f63ec1feee Merge pull request 'Added Item id foreign key in production plans table' (#165) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #165
2026-02-16 05:30:49 +00:00
dhanabalan
b7da185912 Added Item id foreign key in production plans table
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-02-16 10:59:47 +05:30
c63b24e249 Merge pull request 'ranjith-dev' (#164) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #164
2026-01-31 12:35:23 +00:00
dhanabalan
4a796a670a Refactor WebPushSubscription logic to streamline subscription creation
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-31 18:05:10 +05:30
dhanabalan
4577f67d0a Fix CSRF token handling and update fetch URL for push subscription
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
2026-01-31 18:04:26 +05:30
549c22f0e5 Merge pull request 'Fix fetch URL in push notification subscription to include leading slash' (#163) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #163
2026-01-31 12:31:56 +00:00
dhanabalan
be2151a072 Fix fetch URL in push notification subscription to include leading slash
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-31 18:01:42 +05:30
bf055b7672 Merge pull request 'Add print PDF route and update WebPushSubscription logic for user subscriptions' (#162) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #162
2026-01-31 12:30:50 +00:00
dhanabalan
a4251ae532 Add print PDF route and update WebPushSubscription logic for user subscriptions
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-31 18:00:36 +05:30
2eaf01bec8 Merge pull request 'Remove unused CSRF token in push notification registration script' (#161) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #161
2026-01-31 12:29:23 +00:00
dhanabalan
93d55765ae Remove unused CSRF token in push notification registration script
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-31 17:59:00 +05:30
b6478b5feb Merge pull request 'Refactor push notification logic in afterSave method to streamline subscription checks and improve logging' (#160) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #160
2026-01-30 06:51:40 +00:00
dhanabalan
17d54cc52e Refactor push notification logic in afterSave method to streamline subscription checks and improve logging
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-30 12:21:28 +05:30
6d32be91f7 Merge pull request 'Enhance push notification logic in afterSave method to handle missing subscriptions and log warnings' (#159) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #159
2026-01-30 06:43:15 +00:00
dhanabalan
61467d88cd Enhance push notification logic in afterSave method to handle missing subscriptions and log warnings
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-30 12:13:01 +05:30
525d951df7 Merge pull request 'Fix push subscriptions retrieval in afterSave method' (#158) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #158
2026-01-30 06:38:11 +00:00
dhanabalan
af0b17e674 Fix push subscriptions retrieval in afterSave method
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-30 12:07:59 +05:30
1e208bfd7f Merge pull request 'Refactor push notification logic in afterSave method' (#157) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #157
2026-01-30 06:36:02 +00:00
dhanabalan
dd7111a8d9 Refactor push notification logic in afterSave method
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-30 12:05:49 +05:30
8b3a65c4f3 Merge pull request 'Added web subscription logic in web.php' (#156) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #156
2026-01-30 06:23:41 +00:00
dhanabalan
464ee6c3c7 Added web subscription logic in web.php
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Has been cancelled
Laravel Larastan / larastan (pull_request) Has been cancelled
Laravel Pint / pint (pull_request) Has been cancelled
2026-01-30 11:53:23 +05:30
089678dfb3 Merge pull request 'added logs in edit transporter page' (#155) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #155
2026-01-28 07:43:57 +00:00
dhanabalan
984d686182 added logs in edit transporter page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Larastan / larastan (pull_request) Failing after 3m47s
Laravel Pint / pint (pull_request) Failing after 3m59s
2026-01-28 13:13:43 +05:30
afef84e0c7 Merge pull request 'changed message in edit transporter page' (#154) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #154
2026-01-27 08:54:12 +00:00
dhanabalan
fd87748a38 changed message in edit transporter page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 4m47s
Laravel Pint / pint (pull_request) Failing after 4m53s
2026-01-27 14:24:02 +05:30
7c3845ce7c Merge pull request 'chnaged logic in rfq transporter' (#153) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #153
2026-01-27 08:48:10 +00:00
dhanabalan
f9aa6cd1ba chnaged logic in rfq transporter
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Laravel Larastan / larastan (pull_request) Failing after 5m19s
Laravel Pint / pint (pull_request) Failing after 6m39s
2026-01-27 14:17:58 +05:30
97c38d9554 Merge pull request 'chnaged logic in rfq transporter' (#152) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #152
2026-01-27 08:46:03 +00:00
dhanabalan
d743b2df26 chnaged logic in rfq transporter
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 17s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Larastan / larastan (pull_request) Failing after 6m12s
Laravel Pint / pint (pull_request) Failing after 6m58s
2026-01-27 14:15:50 +05:30
2571d0ac57 Merge pull request 'changed logic in edit rfq transporter page' (#151) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #151
2026-01-27 08:44:53 +00:00
dhanabalan
814281a6bf changed logic in edit rfq transporter page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Laravel Larastan / larastan (pull_request) Failing after 5m14s
Laravel Pint / pint (pull_request) Failing after 5m12s
2026-01-27 14:14:41 +05:30
c2b7c43bf0 Merge pull request 'changed logic in edit transporter bid' (#150) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #150
2026-01-27 08:40:34 +00:00
dhanabalan
dc445b17f5 changed logic in edit transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Pint / pint (pull_request) Failing after 3m47s
Laravel Larastan / larastan (pull_request) Failing after 4m43s
2026-01-27 14:10:20 +05:30
d993b64906 Merge pull request 'removed dd in edit transporter page' (#149) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #149
2026-01-27 07:11:19 +00:00
dhanabalan
cd553651f3 removed dd in edit transporter page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Pint / pint (pull_request) Failing after 6m4s
Laravel Larastan / larastan (pull_request) Failing after 8m28s
2026-01-27 12:41:06 +05:30
0c9d5a7964 Merge pull request 'Added dd in edit transporter page' (#148) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #148
2026-01-27 07:02:57 +00:00
dhanabalan
ac20e96358 Added dd in edit transporter page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 20s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Laravel Pint / pint (pull_request) Failing after 5m21s
Laravel Larastan / larastan (pull_request) Failing after 5m34s
2026-01-27 12:32:42 +05:30
aa0b94a975 Merge pull request 'changed logic in edit transporter bid' (#147) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #147
2026-01-27 06:42:20 +00:00
dhanabalan
0fb9c91b28 changed logic in edit transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Laravel Larastan / larastan (pull_request) Failing after 6m8s
Laravel Pint / pint (pull_request) Failing after 6m19s
2026-01-27 12:12:08 +05:30
ae0bc9dcd6 Merge pull request 'removed dd in edit transporter bid' (#146) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #146
2026-01-27 06:34:13 +00:00
dhanabalan
21d602d86a removed dd in edit transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Laravel Pint / pint (pull_request) Failing after 5m14s
Laravel Larastan / larastan (pull_request) Failing after 5m54s
2026-01-27 12:04:03 +05:30
5d8e5d13f5 Merge pull request 'removed _id in model file' (#145) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #145
2026-01-27 06:33:01 +00:00
dhanabalan
06628072dc removed _id in model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 21s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Laravel Larastan / larastan (pull_request) Failing after 7m0s
Laravel Pint / pint (pull_request) Failing after 7m34s
2026-01-27 12:02:35 +05:30
6747abb2db Merge pull request 'changed logic in edit transporter bid' (#144) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #144
2026-01-27 06:29:53 +00:00
dhanabalan
cdf9f60ffd changed logic in edit transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Laravel Pint / pint (pull_request) Failing after 6m3s
Laravel Larastan / larastan (pull_request) Failing after 6m40s
2026-01-27 11:59:33 +05:30
d27ab1d98e Merge pull request 'changed logic in user model' (#143) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #143
2026-01-27 06:24:31 +00:00
dhanabalan
b419a538dc changed logic in user model
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 14s
Laravel Larastan / larastan (pull_request) Failing after 6m20s
Laravel Pint / pint (pull_request) Failing after 6m39s
2026-01-27 11:54:02 +05:30
0f38a9ff1b Merge pull request 'added dd in edit transporter page' (#142) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #142
2026-01-27 06:22:02 +00:00
dhanabalan
fea15e0d1b added dd in edit transporter page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 7m54s
Laravel Pint / pint (pull_request) Failing after 7m53s
2026-01-27 11:51:50 +05:30
667682201a Merge pull request 'changed logic in edit transporter bid page' (#141) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #141
2026-01-27 06:14:17 +00:00
dhanabalan
f5a1e453d5 changed logic in edit transporter bid page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 6m24s
Laravel Pint / pint (pull_request) Failing after 6m29s
2026-01-27 11:44:05 +05:30
e20caa54c7 Merge pull request 'Added PushSubscription method in the user model' (#140) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #140
2026-01-27 06:12:51 +00:00
dhanabalan
fd6149ccbe Added PushSubscription method in the user model
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 20s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Pint / pint (pull_request) Failing after 7m31s
Laravel Larastan / larastan (pull_request) Failing after 8m57s
2026-01-27 11:42:40 +05:30
efa6410cd9 Merge pull request 'chnaged logic in edit transporter bid page' (#139) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #139
2026-01-27 06:11:56 +00:00
dhanabalan
085a4f72fa chnaged logic in edit transporter bid page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Laravel Larastan / larastan (pull_request) Failing after 11m18s
Laravel Pint / pint (pull_request) Failing after 11m30s
2026-01-27 11:41:44 +05:30
eae7e76ea4 Merge pull request 'changed registerPush method logic in push.js' (#138) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #138
2026-01-27 06:00:10 +00:00
dhanabalan
6b41a27d31 changed registerPush method logic in push.js
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Laravel Pint / pint (pull_request) Failing after 8m22s
Laravel Larastan / larastan (pull_request) Failing after 12m1s
2026-01-27 11:24:22 +05:30
30e4415af9 Merge pull request 'change dlogin in web.php and added web push subscription model file' (#137) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 13s
Reviewed-on: #137
2026-01-27 05:31:41 +00:00
dhanabalan
648b676453 change dlogin in web.php and added web push subscription model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Laravel Larastan / larastan (pull_request) Failing after 12m59s
Laravel Pint / pint (pull_request) Failing after 13m9s
2026-01-27 11:01:28 +05:30
40014570c9 Merge pull request 'changed logic in edit transporter bid' (#136) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 2m22s
Reviewed-on: #136
2026-01-27 05:01:14 +00:00
dhanabalan
6f4d81025b changed logic in edit transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 4m44s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 4m56s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 9m23s
Laravel Larastan / larastan (pull_request) Failing after 7m9s
Laravel Pint / pint (pull_request) Failing after 21m44s
2026-01-27 10:30:48 +05:30
c5e45cd6dd Merge pull request 'changed design for notification settings' (#135) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #135
2026-01-24 11:10:03 +00:00
dhanabalan
42bbad16aa changed design for notification settings
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 9s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Laravel Pint / pint (pull_request) Failing after 2m19s
Laravel Larastan / larastan (pull_request) Failing after 2m21s
2026-01-24 16:39:49 +05:30
2d40e51e78 Merge pull request 'changed logic in rfq transporter' (#134) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #134
2026-01-24 10:55:25 +00:00
dhanabalan
3fcc2de515 changed logic in rfq transporter
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Laravel Pint / pint (pull_request) Failing after 2m43s
Laravel Larastan / larastan (pull_request) Failing after 2m58s
2026-01-24 16:25:12 +05:30
98a3c5bc8e Merge pull request 'Added after create logic inside the rfq transporter bid' (#133) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #133
2026-01-24 10:07:07 +00:00
dhanabalan
d14200e40e Added after create logic inside the rfq transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 13s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m14s
Laravel Pint / pint (pull_request) Failing after 2m15s
2026-01-24 15:36:56 +05:30
e969e54f59 Merge pull request 'Added after craete method in transporter bid' (#132) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #132
2026-01-24 09:37:08 +00:00
dhanabalan
a34322c87a Added after craete method in transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 13s
Laravel Larastan / larastan (pull_request) Failing after 2m27s
Laravel Pint / pint (pull_request) Failing after 2m42s
2026-01-24 15:06:54 +05:30
6bad120e70 Merge pull request 'changed logic in transporter bid' (#131) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #131
2026-01-24 09:30:53 +00:00
dhanabalan
547d73e1f4 changed logic in transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Laravel Pint / pint (pull_request) Failing after 2m18s
Laravel Larastan / larastan (pull_request) Failing after 2m22s
2026-01-24 15:00:41 +05:30
02dea13222 Merge pull request 'removed dd in push notification' (#130) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #130
2026-01-24 09:25:29 +00:00
dhanabalan
d93d55bb69 removed dd in push notification
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Laravel Larastan / larastan (pull_request) Failing after 2m25s
Laravel Pint / pint (pull_request) Failing after 2m35s
2026-01-24 14:55:15 +05:30
07c642e3bd Merge pull request 'changed logic in bid transporter page' (#129) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #129
2026-01-24 09:24:07 +00:00
dhanabalan
ad00321dff changed logic in bid transporter page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 2m19s
Laravel Pint / pint (pull_request) Failing after 2m29s
2026-01-24 14:53:56 +05:30
33e3b247b3 Merge pull request 'Addded dd fior checking web push' (#128) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #128
2026-01-24 09:00:56 +00:00
dhanabalan
d333324935 Addded dd fior checking web push
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 9s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 13s
Laravel Larastan / larastan (pull_request) Failing after 2m34s
Laravel Pint / pint (pull_request) Failing after 2m33s
2026-01-24 14:30:44 +05:30
0bcc8d2113 Merge pull request 'changed logic in transporter bid' (#127) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #127
2026-01-24 07:37:14 +00:00
dhanabalan
a1b8cc0eed changed logic in transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 13s
Laravel Larastan / larastan (pull_request) Failing after 2m8s
Laravel Pint / pint (pull_request) Failing after 2m26s
2026-01-24 13:06:45 +05:30
ff607695bc Merge pull request 'changed logic in push alert notification page' (#126) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #126
2026-01-24 07:29:31 +00:00
dhanabalan
d2a2a35410 changed logic in push alert notification page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Laravel Pint / pint (pull_request) Failing after 2m14s
Laravel Larastan / larastan (pull_request) Failing after 2m18s
2026-01-24 12:58:57 +05:30
006857ec89 Merge pull request 'chanaged logic for rfq transporter bid' (#125) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #125
2026-01-24 07:11:20 +00:00
dhanabalan
28503a25c3 chanaged logic for rfq transporter bid
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 13s
Laravel Pint / pint (pull_request) Failing after 2m20s
Laravel Larastan / larastan (pull_request) Failing after 2m22s
2026-01-24 12:41:06 +05:30
107e8cf505 Merge pull request 'changed logic in manifest.json' (#124) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #124
2026-01-24 06:46:50 +00:00
dhanabalan
20b17d446b changed logic in manifest.json
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m9s
Laravel Pint / pint (pull_request) Failing after 2m34s
2026-01-24 12:16:40 +05:30
49d5dfb664 Merge pull request 'Added gcm sender id in manifest.json' (#123) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #123
2026-01-24 06:42:31 +00:00
dhanabalan
0de50e12b8 Added gcm sender id in manifest.json
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 16s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Laravel Pint / pint (pull_request) Failing after 2m8s
Laravel Larastan / larastan (pull_request) Failing after 2m19s
2026-01-24 12:12:04 +05:30
cf097255a0 Merge pull request 'Added service worker js' (#122) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #122
2026-01-24 06:05:03 +00:00
dhanabalan
9767e0547d Added service worker js
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m52s
Laravel Pint / pint (pull_request) Failing after 2m29s
2026-01-24 11:34:50 +05:30
27223612d3 Merge pull request 'changed logic in service worker.js' (#121) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #121
2026-01-24 05:58:44 +00:00
dhanabalan
92da8af6d2 changed logic in service worker.js
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 13s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 2m31s
Laravel Pint / pint (pull_request) Failing after 2m54s
2026-01-24 11:28:29 +05:30
22de1ba081 Merge pull request 'Added has push subscriptions in user model file' (#120) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #120
2026-01-24 04:47:44 +00:00
dhanabalan
1adfd59a0e Added has push subscriptions in user model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Laravel Pint / pint (pull_request) Failing after 2m26s
Laravel Larastan / larastan (pull_request) Failing after 2m35s
2026-01-24 10:17:32 +05:30
d7c2fc3ff9 Merge pull request 'changed logic in invoice validation' (#119) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #119
2026-01-24 04:43:38 +00:00
dhanabalan
92bf1ee401 changed logic in invoice validation
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 2m33s
Laravel Pint / pint (pull_request) Failing after 2m34s
2026-01-24 10:13:24 +05:30
29a7a66ff4 Merge pull request 'Added web push route in web.php' (#118) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #118
2026-01-24 04:40:45 +00:00
dhanabalan
99a605196d Added web push route in web.php
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Laravel Larastan / larastan (pull_request) Failing after 2m15s
Laravel Pint / pint (pull_request) Failing after 2m53s
2026-01-24 10:10:31 +05:30
5f87467dbf Merge pull request 'Added push aert notification page' (#117) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #117
2026-01-24 04:35:34 +00:00
dhanabalan
e075a510d9 Added push aert notification page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m3s
Laravel Pint / pint (pull_request) Failing after 2m9s
2026-01-24 10:05:23 +05:30
c01df679a0 Merge pull request 'Added push alert notification sample' (#116) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #116
2026-01-24 04:34:14 +00:00
dhanabalan
2a7d012ec8 Added push alert notification sample
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Laravel Pint / pint (pull_request) Failing after 2m24s
Laravel Larastan / larastan (pull_request) Failing after 7m9s
2026-01-24 10:04:01 +05:30
4b653f6bb0 Merge pull request 'added web push notification in pwa' (#115) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #115
2026-01-24 04:25:38 +00:00
dhanabalan
d63e8f7a37 added web push notification in pwa
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Pint / pint (pull_request) Failing after 2m11s
Laravel Larastan / larastan (pull_request) Failing after 2m28s
2026-01-24 09:55:23 +05:30
a877623567 Merge pull request 'added package for web push notification' (#114) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #114
2026-01-24 04:23:12 +00:00
dhanabalan
9c4679a5a5 added package for web push notification
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Larastan / larastan (pull_request) Failing after 2m12s
Laravel Pint / pint (pull_request) Failing after 2m12s
2026-01-24 09:52:59 +05:30
e8a6e88eac Merge pull request 'changed logic in push.js' (#113) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #113
2026-01-24 04:17:44 +00:00
dhanabalan
f6f3ab803c changed logic in push.js
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 9s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Larastan / larastan (pull_request) Failing after 2m23s
Laravel Pint / pint (pull_request) Failing after 2m46s
2026-01-24 09:47:32 +05:30
ab49a0fc7c Merge pull request 'Added service worker js and push.js' (#112) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #112
2026-01-23 12:46:22 +00:00
dhanabalan
64b5c129ee Added service worker js and push.js
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Laravel Larastan / larastan (pull_request) Failing after 2m28s
Laravel Pint / pint (pull_request) Failing after 2m37s
2026-01-23 18:16:05 +05:30
e320e4486f Merge pull request 'registered push.js in admin panel provider' (#111) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #111
2026-01-23 12:43:05 +00:00
dhanabalan
955359b92c registered push.js in admin panel provider
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m31s
Laravel Pint / pint (pull_request) Failing after 2m42s
2026-01-23 18:12:54 +05:30
4b5cdef55a Merge pull request 'Added notification settings page' (#110) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #110
2026-01-23 12:41:20 +00:00
dhanabalan
3ffc59f0cf Added notification settings page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Pint / pint (pull_request) Failing after 2m43s
Laravel Larastan / larastan (pull_request) Failing after 2m47s
2026-01-23 18:11:00 +05:30
82a022d3b4 Merge pull request 'removed route logic' (#109) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #109
2026-01-23 11:31:20 +00:00
dhanabalan
9b5e66c834 removed route logic
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 16s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 24s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Laravel Larastan / larastan (pull_request) Failing after 2m34s
Laravel Pint / pint (pull_request) Failing after 2m28s
2026-01-23 17:01:04 +05:30
7ec116ca0b Merge pull request 'Added admin welcome page' (#108) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #108
2026-01-23 11:20:21 +00:00
dhanabalan
7dbeb0afd3 Added admin welcome page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Pint / pint (pull_request) Failing after 2m36s
Laravel Larastan / larastan (pull_request) Failing after 2m54s
2026-01-23 16:50:07 +05:30
048f069dd7 Merge pull request 'Added welcome page in cri' (#107) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #107
2026-01-23 11:02:24 +00:00
dhanabalan
fdfa5d0cf1 Added welcome page in cri
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Larastan / larastan (pull_request) Failing after 2m25s
Laravel Pint / pint (pull_request) Failing after 2m27s
2026-01-23 16:32:02 +05:30
b83e26c9d6 Merge pull request 'changed logic in pwa install' (#106) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #106
2026-01-23 10:10:01 +00:00
dhanabalan
fce45b5386 changed logic in pwa install
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Laravel Pint / pint (pull_request) Failing after 2m33s
Laravel Larastan / larastan (pull_request) Failing after 2m37s
2026-01-23 15:39:48 +05:30
945d50c504 Merge pull request 'ranjith-dev' (#105) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #105
2026-01-23 10:00:31 +00:00
dhanabalan
6a62dce305 Added sticker validation policy file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Larastan / larastan (pull_request) Failing after 2m36s
Laravel Pint / pint (pull_request) Failing after 2m34s
2026-01-23 15:30:20 +05:30
dhanabalan
9ae6dede23 changed logic in rfq chart
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
2026-01-23 15:11:41 +05:30
ae0758a9c0 Merge pull request 'changed logic in rfq transporter bid resource page' (#104) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #104
2026-01-23 09:40:28 +00:00
dhanabalan
2f470c5c54 changed logic in rfq transporter bid resource page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Pint / pint (pull_request) Failing after 2m45s
Laravel Larastan / larastan (pull_request) Failing after 2m57s
2026-01-23 15:10:16 +05:30
238d7bdfa7 Merge pull request 'Added spot rate transport master policy file' (#103) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #103
2026-01-23 09:39:14 +00:00
dhanabalan
529850f0b9 Added spot rate transport master policy file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m29s
Laravel Pint / pint (pull_request) Failing after 2m39s
2026-01-23 15:09:00 +05:30
be1e7f36b2 Merge pull request 'Added request quotation policy file' (#102) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #102
2026-01-23 09:38:06 +00:00
dhanabalan
61637bc3d5 Added request quotation policy file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 13s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Pint / pint (pull_request) Failing after 2m35s
Laravel Larastan / larastan (pull_request) Failing after 2m56s
2026-01-23 15:07:54 +05:30
165b7e6a77 Merge pull request 'Added rfq transporter bid policy file' (#101) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #101
2026-01-23 09:37:20 +00:00
dhanabalan
c248a42a9d Added rfq transporter bid policy file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Laravel Larastan / larastan (pull_request) Failing after 2m22s
Laravel Pint / pint (pull_request) Failing after 2m37s
2026-01-23 15:07:05 +05:30
d0269a646c Merge pull request 'Added rfq chart and rfq rank chart widgets page' (#100) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #100
2026-01-23 07:27:29 +00:00
dhanabalan
aeb49c40eb Added rfq chart and rfq rank chart widgets page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Laravel Larastan / larastan (pull_request) Failing after 2m23s
Laravel Pint / pint (pull_request) Failing after 2m30s
2026-01-23 12:57:18 +05:30
3eccb1c7d5 Merge pull request 'Added rfq dashboard and rfq overview pages' (#99) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #99
2026-01-23 07:26:21 +00:00
dhanabalan
8fc963dc0a Added rfq dashboard and rfq overview pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m24s
Laravel Pint / pint (pull_request) Failing after 2m35s
2026-01-23 12:56:11 +05:30
83888054e9 Merge pull request 'Added rfq transporter bid resource pages' (#98) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #98
2026-01-23 07:23:30 +00:00
dhanabalan
14844f1e1e Added rfq transporter bid resource pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Pint / pint (pull_request) Failing after 2m42s
Laravel Larastan / larastan (pull_request) Failing after 3m9s
2026-01-23 12:53:17 +05:30
22e2fbd25d Merge pull request 'Added rfq transporter bid model file' (#97) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #97
2026-01-23 07:22:02 +00:00
dhanabalan
cfc5845768 Added rfq transporter bid model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m26s
Laravel Pint / pint (pull_request) Failing after 2m46s
2026-01-23 12:51:46 +05:30
d5d1243d5c Merge pull request 'Added rfq transporter bid migration file' (#96) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #96
2026-01-23 07:20:47 +00:00
dhanabalan
f0a6f924d9 Added rfq transporter bid migration file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 2m36s
Laravel Pint / pint (pull_request) Failing after 2m24s
2026-01-23 12:50:34 +05:30
2d2d3ac8c5 Merge pull request 'Added request quotation resource pages' (#95) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #95
2026-01-23 07:18:05 +00:00
dhanabalan
f6f9730587 Added request quotation resource pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 2m37s
Laravel Pint / pint (pull_request) Failing after 3m16s
2026-01-23 12:47:53 +05:30
6e9e57682c Merge pull request 'Added request quotation model file' (#94) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #94
2026-01-23 07:16:21 +00:00
dhanabalan
b42f5ffe84 Added request quotation model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m49s
Laravel Pint / pint (pull_request) Failing after 2m36s
2026-01-23 12:46:11 +05:30
3fa6ca578b Merge pull request 'added request quotation migartion file' (#93) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #93
2026-01-23 07:15:06 +00:00
dhanabalan
376899e277 added request quotation migartion file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Pint / pint (pull_request) Failing after 2m31s
Laravel Larastan / larastan (pull_request) Failing after 3m33s
2026-01-23 12:44:55 +05:30
bc43d5ddf1 Merge pull request 'Added spot rate transport master resource pages' (#92) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #92
2026-01-23 07:11:06 +00:00
dhanabalan
e53fb15c01 Added spot rate transport master resource pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m42s
Laravel Pint / pint (pull_request) Failing after 2m35s
2026-01-23 12:40:53 +05:30
201c55121e Merge pull request 'Added spot rate master model file' (#91) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #91
2026-01-23 07:08:24 +00:00
dhanabalan
953999459e Added spot rate master model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Laravel Pint / pint (pull_request) Failing after 2m34s
Laravel Larastan / larastan (pull_request) Failing after 3m1s
2026-01-23 12:37:59 +05:30
aa91bd80de Merge pull request 'Added spot rate transport master migration file' (#90) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #90
2026-01-23 06:09:48 +00:00
dhanabalan
d2ab947b1d Added spot rate transport master migration file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Laravel Pint / pint (pull_request) Failing after 2m28s
Laravel Larastan / larastan (pull_request) Failing after 2m39s
2026-01-23 11:39:26 +05:30
d4fc6f6f33 Merge pull request 'changed logic for safari browser pwa' (#89) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #89
2026-01-01 08:35:02 +00:00
dhanabalan
9b965d5a2b changed logic for safari browser pwa
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 9s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 9s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Laravel Larastan / larastan (pull_request) Failing after 2m7s
Laravel Pint / pint (pull_request) Failing after 2m15s
2026-01-01 14:04:46 +05:30
dade6a3c0c Merge pull request 'Added logo for the application of pwa' (#88) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #88
2026-01-01 05:49:55 +00:00
dhanabalan
f48de19e0d Added logo for the application of pwa
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Laravel Larastan / larastan (pull_request) Failing after 2m3s
Laravel Pint / pint (pull_request) Failing after 2m3s
2026-01-01 11:19:38 +05:30
d8aea01b26 Merge pull request 'Added manifest.json and changed name of teh application' (#87) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #87
2026-01-01 05:14:18 +00:00
dhanabalan
48ce416cbf Added manifest.json and changed name of teh application
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Pint / pint (pull_request) Failing after 2m5s
Laravel Larastan / larastan (pull_request) Failing after 2m19s
2026-01-01 10:44:01 +05:30
a690faf6d7 Merge pull request 'changed logic for kiosk mode to take print out in sticker validation' (#86) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #86
2025-12-30 11:06:58 +00:00
dhanabalan
39b5cf77e4 changed logic for kiosk mode to take print out in sticker validation
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 15s
Laravel Larastan / larastan (pull_request) Failing after 2m17s
Laravel Pint / pint (pull_request) Failing after 2m19s
2025-12-30 16:36:26 +05:30
dd6cbd92a2 Merge pull request 'Added pdf generate method for sticker validation' (#85) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #85
2025-12-30 09:19:24 +00:00
dhanabalan
46649d0459 Added pdf generate method for sticker validation
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Laravel Pint / pint (pull_request) Failing after 2m38s
Laravel Larastan / larastan (pull_request) Failing after 13m18s
2025-12-30 14:49:11 +05:30
b54a9af78b Merge pull request 'Added sticker validation livewire pages' (#84) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #84
2025-12-30 08:59:00 +00:00
dhanabalan
2f593326e5 Added sticker validation livewire pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m8s
Laravel Pint / pint (pull_request) Failing after 2m23s
2025-12-30 14:28:49 +05:30
57f059aca8 Merge pull request 'Added sticker validation blade file' (#83) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #83
2025-12-30 08:57:51 +00:00
dhanabalan
bb9c344e5b Added sticker validation blade file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m14s
Laravel Pint / pint (pull_request) Failing after 2m8s
2025-12-30 14:27:37 +05:30
5688e93862 Merge pull request 'Added Sticker Validation resource pages' (#82) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #82
2025-12-30 08:56:26 +00:00
dhanabalan
10e595a4a3 Added Sticker Validation resource pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Pint / pint (pull_request) Failing after 2m39s
Laravel Larastan / larastan (pull_request) Failing after 2m57s
2025-12-30 14:26:13 +05:30
8b556d3c9c Merge pull request 'Added Sticker Validation model file' (#81) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #81
2025-12-30 08:55:06 +00:00
dhanabalan
31ab56d46c Added Sticker Validation model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Pint / pint (pull_request) Failing after 2m18s
Laravel Larastan / larastan (pull_request) Failing after 2m25s
2025-12-30 14:24:55 +05:30
091aaaa0d7 Merge pull request 'Added sticker validation migration file' (#80) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #80
2025-12-30 08:53:55 +00:00
dhanabalan
a8f566ca04 Added sticker validation migration file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Larastan / larastan (pull_request) Failing after 2m19s
Laravel Pint / pint (pull_request) Failing after 2m27s
2025-12-30 14:23:41 +05:30
9dd5d04b3c Merge pull request 'Added sticker mapping master importer and exporter' (#79) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #79
2025-12-30 08:46:59 +00:00
dhanabalan
00d9cfc291 Added sticker mapping master importer and exporter
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Pint / pint (pull_request) Failing after 2m13s
Laravel Larastan / larastan (pull_request) Failing after 2m20s
2025-12-30 14:16:41 +05:30
4ac3eb4f2f Merge pull request 'Added sticker mapping master resource pages' (#78) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #78
2025-12-30 08:40:35 +00:00
dhanabalan
7e45c611a0 Added sticker mapping master resource pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Pint / pint (pull_request) Failing after 2m7s
Laravel Larastan / larastan (pull_request) Failing after 2m10s
2025-12-30 14:10:21 +05:30
bcd493901c Merge pull request 'Added sticker mapping master model file' (#77) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #77
2025-12-30 08:39:11 +00:00
dhanabalan
7cab79c7e0 Added sticker mapping master model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 14s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Larastan / larastan (pull_request) Failing after 2m13s
Laravel Pint / pint (pull_request) Failing after 2m11s
2025-12-30 14:08:59 +05:30
af3259a842 Merge pull request 'Added sticker mapping master migration file' (#76) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #76
2025-12-30 08:38:43 +00:00
dhanabalan
2d81d41f34 Added sticker mapping master migration file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 52s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 1m20s
Laravel Larastan / larastan (pull_request) Failing after 2m28s
Laravel Pint / pint (pull_request) Failing after 2m24s
2025-12-30 14:07:53 +05:30
6f41238b1e Merge pull request 'Added validation in importer and exporter of sticker structure details' (#75) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #75
2025-12-25 12:03:45 +00:00
dhanabalan
4daa72db8e Added validation in importer and exporter of sticker structure details
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 9s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 14s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 9s
Laravel Pint / pint (pull_request) Failing after 2m7s
Laravel Larastan / larastan (pull_request) Failing after 2m13s
2025-12-25 17:33:33 +05:30
8779e66a18 Merge pull request 'Added validation logic in sticker detail for importer and exporter' (#74) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #74
2025-12-25 12:01:11 +00:00
dhanabalan
504c125ca8 Added validation logic in sticker detail for importer and exporter
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Laravel Larastan / larastan (pull_request) Failing after 2m8s
Laravel Pint / pint (pull_request) Failing after 2m44s
2025-12-25 17:30:59 +05:30
e0384780dc Merge pull request 'Remove dimage path and image type in sticker detail model file' (#73) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #73
2025-12-25 07:43:39 +00:00
dhanabalan
79f91bf444 Remove dimage path and image type in sticker detail model file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 9s
Laravel Larastan / larastan (pull_request) Failing after 2m20s
Laravel Pint / pint (pull_request) Failing after 2m20s
2025-12-25 13:13:29 +05:30
afbbfe2aca Merge pull request 'Removed image path and image type in sticker detail resource' (#72) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #72
2025-12-25 07:42:34 +00:00
dhanabalan
628d85fda8 Removed image path and image type in sticker detail resource
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 16s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Pint / pint (pull_request) Failing after 2m2s
Laravel Larastan / larastan (pull_request) Failing after 2m11s
2025-12-25 13:12:22 +05:30
4fb04c9fa8 Merge pull request 'removed image type column from sticker details migration' (#71) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #71
2025-12-25 07:40:24 +00:00
dhanabalan
b837a02a5e removed image type column from sticker details migration
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 9s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Pint / pint (pull_request) Failing after 1m55s
Laravel Larastan / larastan (pull_request) Failing after 1m59s
2025-12-25 13:10:13 +05:30
656c58999c Merge pull request 'removed image path column in sticker details' (#70) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #70
2025-12-25 07:36:56 +00:00
dhanabalan
5c403340ca removed image path column in sticker details
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Larastan / larastan (pull_request) Failing after 2m8s
Laravel Pint / pint (pull_request) Failing after 2m14s
2025-12-25 13:06:38 +05:30
102bc62805 Merge pull request 'Commented heading tag on preview' (#69) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #69
2025-12-23 12:23:14 +00:00
dhanabalan
3b02f9e4cd Commented heading tag on preview
Some checks failed
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 20s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Pint / pint (pull_request) Failing after 3m52s
Laravel Larastan / larastan (pull_request) Failing after 4m2s
2025-12-23 17:52:56 +05:30
ef1ad62749 Merge pull request 'removed unwanted file in fields' (#68) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #68
2025-12-23 12:22:21 +00:00
dhanabalan
3d1b60f0cc removed unwanted file in fields
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Pint / pint (pull_request) Failing after 2m45s
Laravel Larastan / larastan (pull_request) Failing after 2m50s
2025-12-23 17:52:06 +05:30
1e0193e6c9 Merge pull request 'Added item and plant models' (#67) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #67
2025-12-23 12:19:20 +00:00
dhanabalan
b0e2e9fe04 Added item and plant models
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Larastan / larastan (pull_request) Failing after 3m51s
Laravel Pint / pint (pull_request) Failing after 3m49s
2025-12-23 17:49:07 +05:30
18c203552c Merge pull request 'Commented Blade File' (#66) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #66
2025-12-23 12:18:05 +00:00
dhanabalan
b3e0db6815 Commented Blade File
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 20s
Laravel Larastan / larastan (pull_request) Failing after 2m40s
Laravel Pint / pint (pull_request) Failing after 2m35s
2025-12-23 17:47:37 +05:30
61190edcce Merge pull request 'changed logic in sticker preview' (#65) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #65
2025-12-23 12:17:23 +00:00
dhanabalan
4a6ced748f changed logic in sticker preview
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 21s
Laravel Pint / pint (pull_request) Failing after 3m4s
Laravel Larastan / larastan (pull_request) Failing after 3m9s
2025-12-23 17:47:02 +05:30
62774aec0f Merge pull request 'changed logic in sticker pdf service' (#64) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #64
2025-12-23 12:16:15 +00:00
dhanabalan
b92419b927 changed logic in sticker pdf service
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Laravel Larastan / larastan (pull_request) Failing after 3m6s
Laravel Pint / pint (pull_request) Failing after 3m4s
2025-12-23 17:46:03 +05:30
44e58d2d78 Merge pull request 'Added show preview method in sticker pdf service' (#63) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 14s
Reviewed-on: #63
2025-12-23 12:04:02 +00:00
dhanabalan
0c7e55595a Added show preview method in sticker pdf service
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 22s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m16s
Laravel Pint / pint (pull_request) Failing after 2m34s
2025-12-23 17:33:48 +05:30
3ac4f88155 Merge pull request 'Added sticker structure preview page blade file' (#62) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #62
2025-12-23 12:00:01 +00:00
dhanabalan
44ed90354d Added sticker structure preview page blade file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 14s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Laravel Larastan / larastan (pull_request) Failing after 2m21s
Laravel Pint / pint (pull_request) Failing after 2m19s
2025-12-23 17:29:49 +05:30
818f8a3e08 Merge pull request 'Added Sticker Preview page custom filament page' (#61) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #61
2025-12-23 11:58:45 +00:00
dhanabalan
a365e4222a Added Sticker Preview page custom filament page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Laravel Larastan / larastan (pull_request) Failing after 2m40s
Laravel Pint / pint (pull_request) Failing after 2m38s
2025-12-23 17:28:31 +05:30
86798212d0 Merge pull request 'Removed sticker mapping master resource files' (#60) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Reviewed-on: #60
2025-12-23 11:25:53 +00:00
dhanabalan
92db525f36 Removed sticker mapping master resource files
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m13s
Laravel Pint / pint (pull_request) Failing after 2m17s
2025-12-23 16:55:41 +05:30
837bd58177 Merge pull request 'Removed model file of sticker mapping master' (#59) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #59
2025-12-23 11:23:13 +00:00
dhanabalan
0c90d51025 Removed model file of sticker mapping master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 21s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 17s
Laravel Pint / pint (pull_request) Failing after 2m33s
Laravel Larastan / larastan (pull_request) Failing after 2m44s
2025-12-23 16:53:02 +05:30
d8b29ba000 Merge pull request 'removed sticker mapping migration file' (#58) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #58
2025-12-23 11:21:54 +00:00
dhanabalan
b3cf28edba removed sticker mapping migration file
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Laravel Larastan / larastan (pull_request) Failing after 2m14s
Laravel Pint / pint (pull_request) Failing after 2m38s
2025-12-23 16:51:33 +05:30
d1db3e0dad Merge pull request 'added null for design element type in resource page' (#57) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #57
2025-12-23 10:57:01 +00:00
dhanabalan
395df5eda1 added null for design element type in resource page
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 17s
Laravel Larastan / larastan (pull_request) Failing after 2m4s
Laravel Pint / pint (pull_request) Failing after 4m17s
2025-12-23 16:26:49 +05:30
f274de00e1 Merge pull request 'added visible to all text boxes based on design element type' (#56) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Reviewed-on: #56
2025-12-23 10:51:15 +00:00
dhanabalan
562dfa5e59 added visible to all text boxes based on design element type
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 20s
Laravel Larastan / larastan (pull_request) Failing after 2m10s
Laravel Pint / pint (pull_request) Failing after 2m9s
2025-12-23 16:21:03 +05:30
f9c6405b61 Merge pull request 'Added curved rectangle in sticker pdf service' (#55) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 13s
Reviewed-on: #55
2025-12-23 09:54:48 +00:00
dhanabalan
6cbccc018e Added curved rectangle in sticker pdf service
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m27s
Laravel Pint / pint (pull_request) Failing after 2m31s
2025-12-23 15:24:37 +05:30
7ec34a04fc Merge pull request 'Added curve radius in sticker details resource pages' (#54) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #54
2025-12-23 09:53:19 +00:00
dhanabalan
d0bd4afe9b Added curve radius in sticker details resource pages
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Gemini PR Review / Gemini PR Review (pull_request) Failing after 8s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Laravel Larastan / larastan (pull_request) Failing after 2m28s
Laravel Pint / pint (pull_request) Failing after 2m22s
2025-12-23 15:23:06 +05:30
9256e1ed12 Merge pull request 'added curve radius in model file of sticker details' (#53) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled
Reviewed-on: #53
2025-12-23 09:52:27 +00:00
dhanabalan
bf2586eabb added curve radius in model file of sticker details
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 13s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Larastan / larastan (pull_request) Failing after 2m21s
Laravel Pint / pint (pull_request) Failing after 2m20s
2025-12-23 15:21:11 +05:30
b334ba60fa Merge pull request 'Added curve radius column in sticker details' (#52) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #52
2025-12-23 09:48:11 +00:00
dhanabalan
c90d48be52 Added curve radius column in sticker details
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 12s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Pint / pint (pull_request) Failing after 2m17s
Laravel Larastan / larastan (pull_request) Failing after 2m48s
2025-12-23 15:17:56 +05:30
8c81c140d1 Merge pull request 'Added logic in pdf controller' (#51) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #51
2025-12-23 06:19:16 +00:00
dhanabalan
560619beb5 Added logic in pdf controller
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 18s
Laravel Larastan / larastan (pull_request) Failing after 2m39s
Laravel Pint / pint (pull_request) Failing after 2m36s
2025-12-23 11:49:01 +05:30
5ff8acac74 Merge pull request 'Modified logic in generate template' (#50) from ranjith-dev into master
All checks were successful
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 11s
Reviewed-on: #50
2025-12-23 05:56:29 +00:00
dhanabalan
9e2ec1bc8b Modified logic in generate template
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 12s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 10s
Gemini PR Review / Gemini PR Review (pull_request) Successful in 19s
Laravel Larastan / larastan (pull_request) Failing after 3m6s
Laravel Pint / pint (pull_request) Failing after 3m4s
2025-12-23 11:26:16 +05:30
128 changed files with 14173 additions and 2407 deletions

View File

@@ -0,0 +1,62 @@
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
class ProductionPlanExport implements FromArray, WithHeadings, WithMapping
{
protected array $data;
protected array $dates;
public function __construct(array $data, array $dates)
{
$this->data = $data;
$this->dates = $dates;
}
public function array(): array
{
return $this->data;
}
public function headings(): array
{
$headings = [
'Plant Name',
'Line Name',
'Item Code',
];
// Add dynamic headings for each date: Target / Produced
foreach ($this->dates as $date) {
$headings[] = $date . ' - Target Plan';
$headings[] = $date . ' - Produced Quantity';
}
return $headings;
}
public function map($row): array
{
$mapped = [
$row['plant_name'] ?? '',
$row['line_name'] ?? '',
$row['item_code'] ?? '',
];
// Add daily target and produced quantity for each date
foreach ($this->dates as $date) {
// $mapped[] = $row['daily_target_dynamic'] ?? 0;
$mapped[] = $row['daily_target_dynamic'][$date] ?? '-';
$mapped[] = $row['produced_quantity'][$date] ?? 0;
}
return $mapped;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Filament\Exports;
use App\Models\EmployeeMaster;
use Filament\Actions\Exports\ExportColumn;
use Filament\Actions\Exports\Exporter;
use Filament\Actions\Exports\Models\Export;
class EmployeeMasterExporter extends Exporter
{
protected static ?string $model = EmployeeMaster::class;
public static function getColumns(): array
{
return [
ExportColumn::make('id')
->label('ID'),
ExportColumn::make('plant.name'),
ExportColumn::make('name'),
ExportColumn::make('code'),
ExportColumn::make('department'),
ExportColumn::make('designation'),
ExportColumn::make('email'),
ExportColumn::make('mobile_number'),
ExportColumn::make('created_at'),
ExportColumn::make('updated_at'),
ExportColumn::make('created_by'),
ExportColumn::make('updated_by'),
ExportColumn::make('deleted_at'),
];
}
public static function getCompletedNotificationBody(Export $export): string
{
$body = 'Your employee master export has completed and ' . number_format($export->successful_rows) . ' ' . str('row')->plural($export->successful_rows) . ' exported.';
if ($failedRowsCount = $export->getFailedRowsCount()) {
$body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to export.';
}
return $body;
}
}

View File

@@ -29,6 +29,8 @@ class StickerDetailExporter extends Exporter
->label('ELEMENT ID'),
ExportColumn::make('element_type')
->label('ELEMENT TYPE'),
ExportColumn::make('characteristics_type')
->label('CHARACTERISTICS TYPE'),
ExportColumn::make('string_value')
->label('STRING VALUE'),
ExportColumn::make('string_font')
@@ -47,6 +49,8 @@ class StickerDetailExporter extends Exporter
->label('SHAPE NAME'),
ExportColumn::make('shape_pen_size')
->label('SHAPE PEN SIZE'),
ExportColumn::make('curve_radius')
->label('CURVE RADIUS'),
ExportColumn::make('shape_x1_value')
->label('SHAPE X1 VALUE'),
ExportColumn::make('shape_y1_value')
@@ -55,10 +59,6 @@ class StickerDetailExporter extends Exporter
->label('SHAPE X2 VALUE'),
ExportColumn::make('shape_y2_value')
->label('SHAPE Y2 VALUE'),
ExportColumn::make('image_path')
->label('IMAGE PATH'),
ExportColumn::make('image_type')
->label('IMAGE TYPE'),
ExportColumn::make('image_x')
->label('IMAGE X'),
ExportColumn::make('image_y')

View File

@@ -21,28 +21,117 @@ class StickerMappingMasterExporter extends Exporter
// Increment and return the row number
return ++$rowNumber;
}),
ExportColumn::make('plant.name')
->label('PLANT'),
ExportColumn::make('item.code')
ExportColumn::make('plant.code')
->label('PLANT CODE'),
ExportColumn::make('itemCharacteristic.item.code')
->label('ITEM CODE'),
ExportColumn::make('sticker1')
->label('STICKER LABEL 1'),
ExportColumn::make('sticker2')
->label('STICKER LABEL 2'),
ExportColumn::make('sticker3')
->label('STICKER LABEL 3'),
ExportColumn::make('sticker4')
->label('STICKER LABEL 4'),
ExportColumn::make('sticker5')
->label('STICKER LABEL 5'),
ExportColumn::make('sticker_structure1_id')
->label('STICKER 1')
->getStateUsing(function ($record) {
return $record->sticker1Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker1_machine_id')
->label('WC STICKER 1')
->getStateUsing(function ($record) {
return $record->sticker1Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker1_print_ip')
->label('STICKER 1 PRINT IP'),
ExportColumn::make('sticker_structure2_id')
->label('STICKER 2')
->getStateUsing(function ($record) {
return $record->sticker2Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker2_machine_id')
->label('WC STICKER 2')
->getStateUsing(function ($record) {
return $record->sticker2Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker2_print_ip')
->label('STICKER 2 PRINT IP'),
ExportColumn::make('sticker_structure3_id')
->label('STICKER 3')
->getStateUsing(function ($record) {
return $record->sticker3Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker3_machine_id')
->label('WC STICKER 3')
->getStateUsing(function ($record) {
return $record->sticker3Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker3_print_ip')
->label('STICKER 3 PRINT IP'),
ExportColumn::make('sticker_structure4_id')
->label('STICKER 4')
->getStateUsing(function ($record) {
return $record->sticker4Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker4_machine_id')
->label('WC STICKER 4')
->getStateUsing(function ($record) {
return $record->sticker4Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker4_print_ip')
->label('STICKER 4 PRINT IP'),
ExportColumn::make('sticker_structure5_id')
->label('STICKER 5')
->getStateUsing(function ($record) {
return $record->sticker5Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker5_machine_id')
->label('WC STICKER 5')
->getStateUsing(function ($record) {
return $record->sticker5Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker5_print_ip')
->label('STICKER 5 PRINT IP'),
ExportColumn::make('sticker_structure6_id')
->label('STICKER 6')
->getStateUsing(function ($record) {
return $record->sticker6Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker6_machine_id')
->label('WC STICKER 6')
->getStateUsing(function ($record) {
return $record->sticker6Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker6_print_ip')
->label('STICKER 6 PRINT IP'),
ExportColumn::make('sticker_structure7_id')
->label('STICKER 7')
->getStateUsing(function ($record) {
return $record->sticker7Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker7_machine_id')
->label('WC STICKER 7')
->getStateUsing(function ($record) {
return $record->sticker2Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker7_print_ip')
->label('STICKER 7 PRINT IP'),
ExportColumn::make('sticker_structure8_id')
->label('STICKER 8')
->getStateUsing(function ($record) {
return $record->sticker8Structure?->sticker_id ?? '-';
}),
ExportColumn::make('sticker8_machine_id')
->label('WC STICKER 8')
->getStateUsing(function ($record) {
return $record->sticker8Machine?->work_center ?? '-';
}),
ExportColumn::make('sticker8_print_ip')
->label('STICKER 8 PRINT IP'),
ExportColumn::make('created_at')
->label('CREATED AT'),
ExportColumn::make('updated_at')
->label('UPDATED AT'),
ExportColumn::make('created_by')
->label('CREATED BY'),
ExportColumn::make('updated_by'),
ExportColumn::make('deleted_at'),
ExportColumn::make('updated_by')
->label('UPDATED BY'),
ExportColumn::make('deleted_at')
->enabledByDefault(false)
->label('DELETED AT'),
];
}

View File

@@ -13,21 +13,43 @@ class StickerStructureDetailExporter extends Exporter
public static function getColumns(): array
{
static $rowNumber = 0;
return [
ExportColumn::make('id')
->label('ID'),
ExportColumn::make('sticker_id'),
ExportColumn::make('sticker_width'),
ExportColumn::make('sticker_height'),
ExportColumn::make('sticker_lmargin'),
ExportColumn::make('sticker_rmargin'),
ExportColumn::make('sticker_tmargin'),
ExportColumn::make('sticker_bmargin'),
ExportColumn::make('created_at'),
ExportColumn::make('updated_at'),
ExportColumn::make('created_by'),
ExportColumn::make('updated_by'),
ExportColumn::make('deleted_at'),
ExportColumn::make('no')
->label('NO')
->state(function ($record) use (&$rowNumber) {
// Increment and return the row number
return ++$rowNumber;
}),
ExportColumn::make('plant.code')
->label('PLANT CODE'),
ExportColumn::make('itemCharacteristic.item.code')
->label('ITEM CODE'),
ExportColumn::make('sticker_id')
->label('STICKER ID'),
ExportColumn::make('sticker_width')
->label('STICKER WIDTH'),
ExportColumn::make('sticker_height')
->label('STICKER HEIGHT'),
ExportColumn::make('sticker_lmargin')
->label('STICKER LEFT MARGIN'),
ExportColumn::make('sticker_rmargin')
->label('STICKER RIGHT MARGIN'),
ExportColumn::make('sticker_tmargin')
->label('STICKER TOP MARGIN'),
ExportColumn::make('sticker_bmargin')
->label('STICKER BOTTOM MARGIN'),
ExportColumn::make('created_at')
->label('CREATED AT'),
ExportColumn::make('updated_at')
->label('UPDATED AT'),
ExportColumn::make('created_by')
->label('CREATED BY'),
ExportColumn::make('updated_by')
->label('UPDATED BY'),
ExportColumn::make('deleted_at')
->enabledByDefault(false)
->label('DELETED AT'),
];
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Filament\Imports;
use App\Models\EmployeeMaster;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
class EmployeeMasterImporter extends Importer
{
protected static ?string $model = EmployeeMaster::class;
public static function getColumns(): array
{
return [
ImportColumn::make('plant')
->requiredMapping()
->relationship()
->rules(['required']),
ImportColumn::make('name'),
ImportColumn::make('code'),
ImportColumn::make('department'),
ImportColumn::make('designation'),
ImportColumn::make('email')
->rules(['email']),
ImportColumn::make('mobile_number'),
ImportColumn::make('created_by'),
ImportColumn::make('updated_by'),
];
}
public function resolveRecord(): ?EmployeeMaster
{
// return EmployeeMaster::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
return new EmployeeMaster();
}
public static function getCompletedNotificationBody(Import $import): string
{
$body = 'Your employee master import has completed and ' . number_format($import->successful_rows) . ' ' . str('row')->plural($import->successful_rows) . ' imported.';
if ($failedRowsCount = $import->getFailedRowsCount()) {
$body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to import.';
}
return $body;
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Imports;
use App\Models\Block;
use App\Models\Item;
use App\Models\Line;
use App\Models\Plant;
use App\Models\ProductionPlan;
@@ -23,11 +24,33 @@ class ProductionPlanImporter extends Importer
public static function getColumns(): array
{
return [
ImportColumn::make('created_at')
// ImportColumn::make('created_at')
// ->requiredMapping()
// ->exampleHeader('Created DateTime')
// ->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
// ->label('Created DateTime')
// ->rules(['required']),
ImportColumn::make('plant')
->requiredMapping()
->exampleHeader('Created DateTime')
->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
->label('Created DateTime')
->exampleHeader('Plant Code')
->example(['1000', '1000'])
->label('Plant Code')
->relationship(resolveUsing: 'code')
->rules(['required']),
ImportColumn::make('line')
->requiredMapping()
->exampleHeader('Line Name')
->example(['4 inch pump line', '4 inch pump line'])
->label('Line Name')
->relationship(resolveUsing: 'name')
->rules(['required']),
ImportColumn::make('item')
->requiredMapping()
->exampleHeader('Item Code')
->example(['123456', '210987'])
->label('Item Code')
->relationship(resolveUsing: 'code')
->rules(['required']),
ImportColumn::make('plan_quantity')
->requiredMapping()
@@ -36,175 +59,111 @@ class ProductionPlanImporter extends Importer
->label('Plan Quantity')
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('production_quantity')
->requiredMapping()
->exampleHeader('Production Quantity')
->example(['0', '0'])
->label('Production Quantity')
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('line')
->requiredMapping()
->exampleHeader('Line Name')
->example(['4 inch pump line', '4 inch pump line'])
->label('Line Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('block_reference')
->requiredMapping() // Or optionalMapping() if not always present
->exampleHeader('Block Name')
->example(['Block A', 'Block A'])
->label('Block Name')
->rules(['required']), // Or remove if not required
ImportColumn::make('shift')
->requiredMapping()
->exampleHeader('Shift Name') //ID
->example(['Day', 'Night']) //'2', '7'
->label('Shift Name') // ID
->relationship(resolveUsing: 'name')
->rules(['required']),
ImportColumn::make('plant')
->requiredMapping()
->exampleHeader('Plant Name')
->example(['Ransar Industries-I', 'Ransar Industries-I'])
->label('Plant Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('updated_at')
->requiredMapping()
->exampleHeader('Updated DateTime')
->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
->label('Updated DateTime')
->rules(['required']),
ImportColumn::make('operator_id')
->requiredMapping()
->exampleHeader('Operator ID')
->example([Filament::auth()->user()->name, Filament::auth()->user()->name])
->label('Operator ID')
->rules(['required']),
// ImportColumn::make('production_quantity')
// ->requiredMapping()
// ->exampleHeader('Production Quantity')
// ->example(['0', '0'])
// ->label('Production Quantity')
// ->numeric()
// ->rules(['required', 'integer']),
// ImportColumn::make('block_reference')
// ->requiredMapping() // Or optionalMapping() if not always present
// ->exampleHeader('Block Name')
// ->example(['Block A', 'Block A'])
// ->label('Block Name')
// ->rules(['required']), // Or remove if not required
// ImportColumn::make('shift')
// ->requiredMapping()
// ->exampleHeader('Shift Name') // ID
// ->example(['Day', 'Night']) // '2', '7'
// ->label('Shift Name') // ID
// ->relationship(resolveUsing: 'name')
// ->rules(['required']),
// ImportColumn::make('updated_at')
// ->requiredMapping()
// ->exampleHeader('Updated DateTime')
// ->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
// ->label('Updated DateTime')
// ->rules(['required']),
// ImportColumn::make('operator_id')
// ->requiredMapping()
// ->exampleHeader('Operator ID')
// ->example([Filament::auth()->user()->name, Filament::auth()->user()->name])
// ->label('Operator ID')
// ->rules(['required']),
];
}
public function resolveRecord(): ?ProductionPlan
{
$warnMsg = [];
$plant = Plant::where('name', $this->data['plant'])->first();
$plantCod = $this->data['plant'];
$itemCod = $this->data['item'];
$plant = null;
$line = null;
$block = null;
if (!$plant) {
$warnMsg[] = "Plant not found";
if (Str::length($plantCod) < 4 || ! is_numeric($plantCod) || ! preg_match('/^[1-9]\d{3,}$/', $plantCod)) {
$warnMsg[] = 'Invalid plant code found';
} else {
$plant = Plant::where('code', $plantCod)->first();
}
else {
if (! $plant) {
$warnMsg[] = 'Plant not found';
} else {
$line = Line::where('name', $this->data['line'])->where('plant_id', $plant->id)->first();
//block_reference
$block = Block::where('name', $this->data['block_reference'])->where('plant_id', $plant->id)->first();
}
if (!$line) {
$warnMsg[] = "Line not found";
}
$shift = null;
if (!$block) {
$warnMsg[] = "Block not found";
}
else {
$shift = Shift::where('name', $this->data['shift'])->where('plant_id', $plant->id)->where('block_id', $block->id)->first();
}
//$shift = Shift::where('id', $this->data['shift'])->where('plant_id', $plant->id)->first();
if (!$shift) {
$warnMsg[] = "Shift not found";
}
if (Str::length($this->data['plan_quantity']) < 0 || !is_numeric($this->data['plan_quantity']) || $this->data['plan_quantity'] <= 0) {
$warnMsg[] = "Invalid plan quantity found";
}
if (Str::length($this->data['production_quantity']) < 0 || !is_numeric($this->data['production_quantity']) || $this->data['production_quantity'] < 0) {
$warnMsg[] = "Invalid production quantity found";
}
$fromDate = $this->data['created_at'];
$toDate = $this->data['updated_at'];
$formats = ['d-m-Y H:i', 'd-m-Y H:i:s']; //'07-05-2025 08:00' or '07-05-2025 08:00:00'
$fdateTime = null;
$tdateTime = null;
// Try parsing with multiple formats
foreach ($formats as $format) {
try {
$fdateTime = Carbon::createFromFormat($format, $fromDate);
break;
} catch (\Exception $e) {
// Optionally collect warning messages
// $warnMsg[] = "Date format mismatch with format: $format";
}
if (! $line) {
$warnMsg[] = 'Line not found';
}
foreach ($formats as $format) {
try {
$tdateTime = Carbon::createFromFormat($format, $toDate);
break;
} catch (\Exception $e) {
// Optionally collect warning messages
// $warnMsg[] = "Date format mismatch with format: $format";
}
if (Str::length($itemCod) < 6 || ! is_numeric($itemCod)) {
$warnMsg[] = 'Invalid item code found';
} else {
$item = Item::where('code', $itemCod)->first();
}
$fDateOnly = '';
if (!isset($fdateTime)) {
// throw new \Exception('Invalid date time format');
$warnMsg[] = "Invalid 'Created DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
}
else {
$fDateOnly = $fdateTime->toDateString();
}
if (!isset($tdateTime)) {
$warnMsg[] = "Invalid 'Updated DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
if (! $item) {
$warnMsg[] = 'Item not found';
}
if (isset($fdateTime) && isset($tdateTime)) {
if ($fdateTime->greaterThan($tdateTime)) {
$warnMsg[] = "'Created DataTime' is greater than 'Updated DateTime'.";
}
$plantId = $plant->id;
$itemAgaPlant = Item::where('plant_id', $plantId)->where('code', $itemCod)->first();
if(!$itemAgaPlant){
$warnMsg[] = 'Item not found against plant code';
}
// if (!$fromDate) {
// $warnMsg[] = "Invalid 'Created DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
// }
// else if (!$toDate) {
// $warnMsg[] = "Invalid 'Updated DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
// }
$user = Filament::auth()->user();
$user = User::where('name', $this->data['operator_id'])->first();
if (!$user) {
$warnMsg[] = "Operator ID not found";
$operatorName = $user->name;
if (Str::length($this->data['plan_quantity']) < 0 || ! is_numeric($this->data['plan_quantity']) || $this->data['plan_quantity'] <= 0) {
$warnMsg[] = 'Invalid plan quantity found';
}
if (!empty($warnMsg)) {
if (! empty($warnMsg)) {
throw new RowImportFailedException(implode(', ', $warnMsg));
}
else { //if (empty($warnMsg))
} else {
$productionPlan = ProductionPlan::where('plant_id', $plant->id)
->where('shift_id', $shift->id)
->where('line_id', $line->id)
->whereDate('created_at', $fDateOnly)
// ->where('plan_quantity', $productionQuantity->plan_quantity)
->latest()
->first();
->where('line_id', $line->id)
->where('item_id', $itemAgaPlant->id)
->latest()
->first();
if ($productionPlan) {
// if($productionPlan->production_quantity)
// {
// throw new RowImportFailedException("{$productionPlan->created_at}, {$productionPlan->production_quantity}");
// }
// $warnMsg[] = "Production plan already exist on '{$fDateOnly}'!";
$productionPlan->update([
'plan_quantity' => $this->data['plan_quantity'],
// 'production_quantity' => $productionPlan->production_quantity,
// 'created_at' => $productionPlan->created_at,//$fdateTime->format('Y-m-d H:i:s'),
// 'updated_at' => $tdateTime->format('Y-m-d H:i:s'),
'operator_id' => $this->data['operator_id'],
'operator_id' => $operatorName,
]);
$productionPlan->save();
return null;
}
}
@@ -212,28 +171,23 @@ class ProductionPlanImporter extends Importer
ProductionPlan::updateOrCreate([
'plant_id' => $plant->id,
'line_id' => $line->id,
'shift_id' => $shift->id,
'item_id' => $itemAgaPlant->id,
// 'shift_id' => $shift->id,
'plan_quantity' => $this->data['plan_quantity'],
'production_quantity' => $this->data['production_quantity'],
'created_at' => $fdateTime->format('Y-m-d H:i:s'),//$this->data['created_at'],
'updated_at' => $tdateTime->format('Y-m-d H:i:s'),//$this->data['updated_at'],
'operator_id' => $this->data['operator_id'],
'created_at' =>now(),
'updated_at' => now(),
'operator_id' => $operatorName,
]);
return null;
// return ProductionPlan::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
// return new ProductionPlan();
return null;
}
public static function getCompletedNotificationBody(Import $import): string
{
$body = 'Your production plan import has completed and ' . number_format($import->successful_rows) . ' ' . str('row')->plural($import->successful_rows) . ' imported.';
$body = 'Your production plan import has completed and '.number_format($import->successful_rows).' '.str('row')->plural($import->successful_rows).' imported.';
if ($failedRowsCount = $import->getFailedRowsCount()) {
$body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to import.';
$body .= ' '.number_format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to import.';
}
return $body;

View File

@@ -2,10 +2,14 @@
namespace App\Filament\Imports;
use App\Models\Plant;
use App\Models\StickerDetail;
use App\Models\StickerStructureDetail;
use App\Models\User;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
use Filament\Actions\Imports\Exceptions\RowImportFailedException;
class StickerDetailImporter extends Importer
{
@@ -14,50 +18,295 @@ class StickerDetailImporter extends Importer
public static function getColumns(): array
{
return [
ImportColumn::make('stickerStructureDetail')
ImportColumn::make('sticker_structure_detail_id')
->requiredMapping()
->relationship()
->exampleHeader('Sticker ID')
->example('123456')
->label('STICKER ID')
->rules(['required']),
ImportColumn::make('design_element_type'),
ImportColumn::make('element_id'),
ImportColumn::make('element_type'),
ImportColumn::make('string_value'),
ImportColumn::make('string_font'),
ImportColumn::make('string_size'),
ImportColumn::make('element_colour'),
ImportColumn::make('string_align'),
ImportColumn::make('string_x_value'),
ImportColumn::make('string_y_value'),
ImportColumn::make('shape_name'),
ImportColumn::make('shape_pen_size'),
ImportColumn::make('shape_x1_value'),
ImportColumn::make('shape_y1_value'),
ImportColumn::make('shape_x2_value'),
ImportColumn::make('shape_y2_value'),
ImportColumn::make('image_path'),
ImportColumn::make('image_type'),
ImportColumn::make('image_x'),
ImportColumn::make('image_y'),
ImportColumn::make('image_width'),
ImportColumn::make('image_height'),
ImportColumn::make('qr_value'),
ImportColumn::make('qr_align'),
ImportColumn::make('qr_size'),
ImportColumn::make('qr_x_value'),
ImportColumn::make('qr_y_value'),
ImportColumn::make('created_by'),
ImportColumn::make('updated_by'),
ImportColumn::make('design_element_type')
->requiredMapping()
->exampleHeader('Design Element Type')
->label('DESIGN ELEMENT TYPE')
->example('Text/Shape/Image/QR'),
ImportColumn::make('element_id')
->requiredMapping()
->exampleHeader('Element ID')
->label('ELEMENT ID')
->example('001'),
ImportColumn::make('element_type')
->requiredMapping()
->exampleHeader('Element Type')
->label('ELEMENT TYPE')
->example('Static/Dynamic'),
ImportColumn::make('characteristics_type')
->requiredMapping()
->exampleHeader('Characteristics Type')
->label('CHARACTERISTICS TYPE')
->example('ZMM values'),
ImportColumn::make('string_value')
->requiredMapping()
->exampleHeader('String Value')
->label('STRING VALUE')
->example('1'),
ImportColumn::make('string_font')
->requiredMapping()
->exampleHeader('String Font')
->label('STRING FONT')
->example('Arial'),
ImportColumn::make('string_size')
->requiredMapping()
->exampleHeader('String Size')
->label('STRING SIZE')
->example('12'),
ImportColumn::make('element_colour')
->requiredMapping()
->exampleHeader('Element Colour')
->label('ELEMENT COLOUR')
->example('Black'),
ImportColumn::make('string_align')
->requiredMapping()
->exampleHeader('String Align')
->label('STRING ALIGN')
->example('Left/Center/Right'),
ImportColumn::make('string_x_value')
->requiredMapping()
->exampleHeader('String X Value')
->label('STRING X VALUE')
->example('10'),
ImportColumn::make('string_y_value')
->requiredMapping()
->exampleHeader('String Y Value')
->label('STRING Y VALUE')
->example('20'),
ImportColumn::make('shape_name')
->requiredMapping()
->exampleHeader('Shape Name')
->label('SHAPE NAME')
->example('Line/Rectangle/CurvedRectangle'),
ImportColumn::make('shape_pen_size')
->requiredMapping()
->exampleHeader('Shape Pen Size')
->label('SHAPE PEN SIZE')
->example('0.3'),
ImportColumn::make('curve_radius')
->requiredMapping()
->exampleHeader('Curve Radius')
->label('CURVE RADIUS')
->example('3'),
ImportColumn::make('shape_x1_value')
->requiredMapping()
->exampleHeader('Shape X1 Value')
->label('SHAPE X1 VALUE')
->example('10'),
ImportColumn::make('shape_y1_value')
->requiredMapping()
->exampleHeader('Shape Y1 Value')
->label('SHAPE Y1 VALUE')
->example('20'),
ImportColumn::make('shape_x2_value')
->requiredMapping()
->exampleHeader('Shape X2 Value')
->label('SHAPE X2 VALUE')
->example('30'),
ImportColumn::make('shape_y2_value')
->requiredMapping()
->exampleHeader('Shape Y2 Value')
->label('SHAPE Y2 VALUE')
->example('40'),
ImportColumn::make('image_x')
->requiredMapping()
->exampleHeader('Image X')
->label('IMAGE X')
->example('15'),
ImportColumn::make('image_y')
->requiredMapping()
->exampleHeader('Image Y')
->label('IMAGE Y')
->example('25'),
ImportColumn::make('image_width')
->requiredMapping()
->exampleHeader('Image Width')
->label('IMAGE WIDTH')
->example('100'),
ImportColumn::make('image_height')
->requiredMapping()
->exampleHeader('Image Height')
->label('IMAGE HEIGHT')
->example('100'),
ImportColumn::make('qr_value')
->requiredMapping()
->exampleHeader('QR Value')
->label('QR VALUE')
->example('246118|53246735267'),
ImportColumn::make('qr_align')
->requiredMapping()
->exampleHeader('QR Align')
->label('QR ALIGN')
->example('Left/Center/Right'),
ImportColumn::make('qr_size')
->requiredMapping()
->exampleHeader('QR Size')
->label('QR SIZE')
->example('10'),
ImportColumn::make('qr_x_value')
->requiredMapping()
->exampleHeader('QR X Value')
->label('QR X VALUE')
->example('30'),
ImportColumn::make('qr_y_value')
->requiredMapping()
->exampleHeader('QR Y Value')
->label('QR Y VALUE')
->example('40'),
ImportColumn::make('created_by')
->requiredMapping()
->exampleHeader('Created By')
->label('CREATED BY')
->example('RAW001234'),
];
}
public function resolveRecord(): ?StickerDetail
{
// return StickerDetail::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
return new StickerDetail();
$warnMsg = [];
$sticker = $this->data['sticker_structure_detail_id'] ?? null;
$stickerCode = StickerStructureDetail::where('sticker_id', $sticker)->first();
if (!$stickerCode) {
$warnMsg[] = "Sticker Id not found in Sticker Structure Detail";
}
$stickerId = $stickerCode->id;
$user = User::where('name', $this->data['created_by'])->first();
if (!$user) {
$warnMsg[] = "User not found";
}
$designType = strtolower($this->data['design_element_type'] ?? '');
$rules = [
'text' => [
'required' => ['string_x_value', 'string_y_value'],
'allowed' => [
'string_value',
'string_font',
'string_size',
'string_align',
'string_colour',
'string_x_value',
'string_y_value',
],
],
'image' => [
'required' => ['image_x', 'image_y', 'image_width', 'image_height'],
'allowed' => [
'image_x',
'image_y',
'image_width',
'image_height',
],
],
'shape' => [
'required' => ['shape_name', 'shape_pen_size', 'shape_x1_value', 'shape_y1_value', 'shape_x2_value', 'shape_y2_value'],
'allowed' => [
'shape_name',
'shape_pen_size',
'curve_radius',
'shape_x1_value',
'shape_y1_value',
'shape_x2_value',
'shape_y2_value',
],
],
'qr' => [
'required' => ['qr_value', 'qr_x_value', 'qr_y_value', 'qr_size'],
'allowed' => [
'qr_value',
'qr_align',
'qr_size',
'qr_x_value',
'qr_y_value',
],
],
];
if (!isset($rules[$designType])) {
$warnMsg[] = "Invalid Design Element Type: {$designType}";
}
if (isset($rules[$designType])) {
foreach ($rules[$designType]['required'] as $field) {
if (empty($this->data[$field])) {
$warnMsg[] = ucfirst($designType) . " requires {$field}";
}
}
}
$allElementFields = [
'string_value','string_font','string_size','string_align','string_colour',
'string_x_value','string_y_value',
'image_x','image_y','image_width','image_height',
'shape_name','shape_pen_size','curve_radius',
'shape_x1_value','shape_y1_value','shape_x2_value','shape_y2_value',
'qr_value','qr_align','qr_size','qr_x_value','qr_y_value',
];
if (isset($rules[$designType])) {
$allowed = $rules[$designType]['allowed'];
foreach ($allElementFields as $field) {
if (!in_array($field, $allowed, true) && !empty($this->data[$field])) {
$warnMsg[] = "Field {$field} is not allowed for {$designType} element";
}
}
}
if (!empty($warnMsg)) {
throw new RowImportFailedException(implode(' | ', $warnMsg));
}
StickerDetail::Create([
'sticker_structure_detail_id' => $stickerId,
'design_element_type' => $this->data['design_element_type'],
'element_id' => $this->data['element_id'],
'element_type' => $this->data['element_type'],
'characteristics_type' => $this->data['characteristics_type'],
'string_value' => $this->data['string_value'],
'string_font' => $this->data['string_font'],
'string_size' => $this->data['string_size'],
'element_colour' => $this->data['element_colour'],
'string_align' => $this->data['string_align'],
'string_x_value' => $this->data['string_x_value'],
'string_y_value' => $this->data['string_y_value'],
'shape_name' => $this->data['shape_name'],
'shape_pen_size' => $this->data['shape_pen_size'],
'curve_radius' => $this->data['curve_radius'],
'shape_x1_value' => $this->data['shape_x1_value'],
'shape_y1_value' => $this->data['shape_y1_value'],
'shape_x2_value' => $this->data['shape_x2_value'],
'shape_y2_value' => $this->data['shape_y2_value'],
'image_x' => $this->data['image_x'],
'image_y' => $this->data['image_y'],
'image_width' => $this->data['image_width'],
'image_height' => $this->data['image_height'],
'qr_value' => $this->data['qr_value'],
'qr_align' => $this->data['qr_align'],
'qr_size' => $this->data['qr_size'],
'qr_x_value' => $this->data['qr_x_value'],
'qr_y_value' => $this->data['qr_y_value'],
'created_by' => $this->data['created_by'],
]);
return null;
//return new StickerDetail();
}
public static function getCompletedNotificationBody(Import $import): string

View File

@@ -14,43 +14,56 @@ class StickerMappingMasterImporter extends Importer
public static function getColumns(): array
{
return [
ImportColumn::make('plant')
ImportColumn::make('plant_id')
->requiredMapping()
->exampleHeader('Plant Name')
->example('Ransar Industries-I')
->label('Plant Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('item')
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('item_id')
->requiredMapping()
->exampleHeader('Item Code')
->example('630987')
->label('Item Code')
->relationship(resolveUsing:'code')
->rules(['required']),
ImportColumn::make('sticker1')
->label('Sticker Label 1')
->exampleHeader('Sticker Label 1')
->example('Label 1')
->rules(['required']),
ImportColumn::make('sticker2')
->label('Sticker Label 2')
->exampleHeader('Sticker Label 2')
->example('601468'),
ImportColumn::make('sticker3')
->label('Sticker Label 3')
->exampleHeader('Sticker Label 3'),
//->example(''),
ImportColumn::make('sticker4')
->label('Sticker Label 4')
->exampleHeader('Sticker Label 4'),
ImportColumn::make('sticker5')
->label('Sticker Label 5')
->exampleHeader('Sticker Label 5'),
ImportColumn::make('created_by')
->label('Created By')
->exampleHeader('Created By'),
// ImportColumn::make('updated_by'),
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('sticker1'),
ImportColumn::make('sticker1_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker1_print_ip'),
ImportColumn::make('sticker2'),
ImportColumn::make('sticker2_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker2_print_ip'),
ImportColumn::make('sticker3'),
ImportColumn::make('sticker3_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker3_print_ip'),
ImportColumn::make('sticker4'),
ImportColumn::make('sticker4_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker4_print_ip'),
ImportColumn::make('sticker5'),
ImportColumn::make('sticker5_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker5_print_ip'),
ImportColumn::make('sticker6'),
ImportColumn::make('sticker6_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker6_print_ip'),
ImportColumn::make('sticker7'),
ImportColumn::make('sticker7_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker7_print_ip'),
ImportColumn::make('sticker8'),
ImportColumn::make('sticker8_machine_id')
->numeric()
->rules(['integer']),
ImportColumn::make('sticker8_print_ip'),
ImportColumn::make('created_by'),
ImportColumn::make('updated_by'),
];
}

View File

@@ -2,10 +2,15 @@
namespace App\Filament\Imports;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\Plant;
use App\Models\StickerStructureDetail;
use App\Models\User;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
use Filament\Actions\Imports\Exceptions\RowImportFailedException;
class StickerStructureDetailImporter extends Importer
{
@@ -14,26 +19,133 @@ class StickerStructureDetailImporter extends Importer
public static function getColumns(): array
{
return [
ImportColumn::make('sticker_id'),
ImportColumn::make('sticker_width'),
ImportColumn::make('sticker_height'),
ImportColumn::make('sticker_lmargin'),
ImportColumn::make('sticker_rmargin'),
ImportColumn::make('sticker_tmargin'),
ImportColumn::make('sticker_bmargin'),
ImportColumn::make('created_by'),
ImportColumn::make('updated_by'),
ImportColumn::make('plant')
->requiredMapping()
->exampleHeader('Plant Code')
->example('1000')
->label('PLANT CODE')
->relationship(resolveUsing: 'code')
->rules(['required']),
ImportColumn::make('item_characteristic_id')
->requiredMapping()
->exampleHeader('Item Code')
->example('123456')
->label('ITEM CODE')
->rules(['required']),
ImportColumn::make('sticker_id')
->requiredMapping()
->exampleHeader('Sticker ID')
->example('123456')
->label('STICKER ID')
->rules(['required']),
ImportColumn::make('sticker_width')
->requiredMapping()
->exampleHeader('Sticker Width')
->example('90')
->label('STICKER WIDTH')
->rules(['required']),
ImportColumn::make('sticker_height')
->requiredMapping()
->exampleHeader('Sticker Height')
->example('90')
->label('STICKER HEIGHT')
->rules(['required']),
ImportColumn::make('sticker_lmargin')
->requiredMapping()
->exampleHeader('Sticker Left Margin')
->example('0')
->label('STICKER LEFT MARGIN')
->rules(['required']),
ImportColumn::make('sticker_rmargin')
->requiredMapping()
->exampleHeader('Sticker Right Margin')
->example('0')
->label('STICKER RIGHT MARGIN')
->rules(['required']),
ImportColumn::make('sticker_tmargin')
->requiredMapping()
->exampleHeader('Sticker Top Margin')
->example('0')
->label('STICKER TOP MARGIN')
->rules(['required']),
ImportColumn::make('sticker_bmargin')
->requiredMapping()
->exampleHeader('Sticker Bottom Margin')
->example('0')
->label('STICKER BOTTOM MARGIN')
->rules(['required']),
ImportColumn::make('created_by')
->requiredMapping()
->exampleHeader('Created By')
->example('RAW001234')
->label('CREATED BY')
->rules(['required']),
];
}
public function resolveRecord(): ?StickerStructureDetail
{
// return StickerStructureDetail::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
$warnMsg = [];
return new StickerStructureDetail();
$plant = Plant::where('code', $this->data['plant'])->first();
if (!$plant) {
$warnMsg[] = "Plant code not found";
}
// $item = null;
// if ($plant) {
// $item = Item::where('code', $this->data['itemCharacteristic.item'])->where('plant_id', $plant->id)->first();
// }
// if (!$item) {
// $warnMsg[] = "Item not found";
// }
$itemCode = $this->data['item_characteristic_id'] ?? null;
$item = Item::where('code', $itemCode)->first();
if (!$item) {
$warnMsg[] = "Item not found";
}
$itemChar = ItemCharacteristic::where('item_id', $item->id)->first();
if (!$itemChar) {
$warnMsg[] = "Item not found in item characteristic";
}
$user = User::where('name', $this->data['created_by'])->first();
if (!$user) {
$warnMsg[] = "User not found";
}
if (!empty($warnMsg)) {
throw new RowImportFailedException(implode(', ', $warnMsg));
}
else { //if (empty($warnMsg))
$stickerId = StickerStructureDetail::where('sticker_id', $this->data['sticker_id'])
->first();
if ($stickerId) {
throw new RowImportFailedException("Sticker ID already exist!");
}
}
StickerStructureDetail::Create([
'plant_id' => $plant->id,
'item_characteristic_id' => $itemChar->id,
'sticker_id' => $this->data['sticker_id'],
'sticker_width' => $this->data['sticker_width'],
'sticker_height' => $this->data['sticker_height'],
'sticker_lmargin' => $this->data['sticker_lmargin'],
'sticker_rmargin' => $this->data['sticker_rmargin'],
'sticker_tmargin' => $this->data['sticker_tmargin'],
'sticker_bmargin' => $this->data['sticker_bmargin'],
'created_by' => $this->data['created_by'],
]);
return null;
//return new StickerStructureDetail();
}
public static function getCompletedNotificationBody(Import $import): string

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Filament\Pages;
use Filament\Pages\Page;
class NotificationSettings extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.notification-settings';
public static function getScripts(): array
{
return [
asset('js/push.js')
];
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace App\Filament\Pages;
use App\Models\CustomerPoMaster;
use App\Models\Plant;
use App\Models\ProductionPlan;
use App\Models\WireMasterPacking;
use Filament\Facades\Filament;
use Filament\Pages\Page;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Form;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ViewField;
use Filament\Notifications\Notification;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Hidden;
class ProductionCalender extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.production-calender';
use InteractsWithForms;
protected $listeners = ['setWorkingDays'];
public $pId;
public array $filters = [];
public function setWorkingDays($days = null)
{
$this->form->fill([
'working_days' => $days ?? 0,
]);
}
public function form(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
Select::make('plant_id')
->label('Plant')
->reactive()
//->options(Plant::pluck('name', 'id'))
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
})
->columnSpan(['default' => 10, 'sm' => 7])
->required()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('working_days', null);
}),
TextInput::make('working_days')
->label('No. of Working Days')
->numeric()
->readOnly()
->columnSpan(['default' => 10, 'sm' => 2])
->required()
->minValue(0)
->maxValue(31)
->placeholder('Enter working days')
->id('working_days'),
Hidden::make('month')
->label('Month')
->id('month'),
Hidden::make('year')
->label('Year')
->id('year'),
Hidden::make('selected_dates')
->label('Selected Dates')
->id('selected_dates'),
ViewField::make('save')
->view('forms.save')
->columnSpan(['default' => 10, 'sm' => 1]),
ViewField::make('calendar')
->view('forms.calendar')
->columnspan(10),
])
->columns(10)
]);
}
public function saveWorkingDays(){
$plantId = $this->filters['plant_id'] ?? null;
$workingDays = $this->filters['working_days'] ?? null;
$month = $this->filters['month'] ?? null;
$year = $this->filters['year'] ?? null;
$dates = $this->filters['selected_dates'] ?? null;
if (!$plantId) {
Notification::make()
->title('Unknown Plant')
->body("Please select a plant first!")
->danger()
->send();
return;
}
else if (!$workingDays) {
Notification::make()
->title('Unknown Working Days')
->body("Working days can't be empty!")
->danger()
->send();
return;
}
else if (!$month) {
Notification::make()
->title('Unknown Month')
->body("month can't be empty!")
->danger()
->send();
return;
}
else if (!$year) {
Notification::make()
->title('Unknown Year')
->body("Year can't be empty!")
->danger()
->send();
return;
}
$updated = ProductionPlan::where('plant_id', $plantId)
->whereMonth('created_at', $month)
->whereYear('created_at', $year)
->update([
'working_days' => $workingDays,
'leave_dates' => $dates,
'updated_at' => now(),
]);
if ($updated) {
Notification::make()
->title('Success')
->body("Working days updated successfully!")
->success()
->send();
} else {
Notification::make()
->title('No Records Updated')
->body("No production plans found for this plant and month.")
->warning()
->send();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,173 @@
<?php
namespace App\Filament\Pages;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms\Components\DatePicker;
use Filament\Pages\Page;
use Filament\Forms\Form;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
class ProductionTarget extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.production-target';
public array $filters = [];
public function form(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
Select::make('plant_id')
->label('Plant')
->reactive()
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
})
->required()
->afterStateUpdated(function ($state, callable $get, $set) {
$set('line_id', null);
$set('year', null);
$set('month', null);
$this->dispatch('loadData',$state, '', '', '');
}),
Select::make('line_id')
->label('Line')
->required()
->columnSpan(1)
->options(function (callable $get) {
if (!$get('plant_id')) {
return [];
}
return \App\Models\Line::where('plant_id', $get('plant_id'))
->pluck('name', 'id')
->toArray();
})
->reactive()
->afterStateUpdated(function ($state, callable $get, $set) {
$plantId = $get('plant_id');
$set('year', null);
$set('month', null);
$this->dispatch('loadData',$plantId, $state, '', '');
}),
Select::make('year')
->label('Year')
->reactive()
->options([
'2026' => '2026',
'2027' => '2027',
'2028' => '2028',
'2029' => '2029',
'2030' => '2030',
'2031' => '2031',
'2032' => '2032',
'2033' => '2033',
'2034' => '2034',
'2035' => '2035',
'2036' => '2036',
'2037' => '2037',
'2038' => '2038',
'2039' => '2039',
'2040' => '2040',
])
->required()
->afterStateUpdated(function ($state, callable $get, $set) {
$set('month', null);
$plantId = $get('plant_id');
$lineId = $get('line_id');
$this->dispatch('loadData',$plantId, $lineId, $state, '');
}),
Select::make('month')
->label('Month')
->reactive()
->options([
'01' => 'January',
'02' => 'February',
'03' => 'March',
'04' => 'April',
'05' => 'May',
'06' => 'June',
'07' => 'July',
'08' => 'August',
'09' => 'September',
'10' => 'October',
'11' => 'November',
'12' => 'December',
])
->required()
->afterStateUpdated(function ($state, callable $get) {
$plantId = $get('plant_id');
$lineId = $get('line_id');
// $month = $get('month');
$year = $get('year');
$month = (int) $get('month');
if (!$month) {
return;
}
$this->dispatch('loadData', $plantId, $lineId, $month, $year);
}),
])
->columns(4)
]);
}
public function export(){
$plantId = $this->filters['plant_id'] ?? null;
$lineId = $this->filters['line_id'] ?? null;
$year = $this->filters['year'] ?? null;
$month = $this->filters['month'] ?? null;
if (! $plantId) {
Notification::make()
->title('Plant')
->body("please select plant to export data..!")
->danger()
->send();
return;
}
else if (! $lineId) {
Notification::make()
->title('Line')
->body("please select line to export data..!")
->danger()
->send();
return;
}
else if (! $year) {
Notification::make()
->title('Year')
->body("please select year to export data..!")
->danger()
->send();
return;
}
else if (! $month) {
Notification::make()
->title('Month')
->body("please select month to export data..!")
->danger()
->send();
return;
}
$this->dispatch('loadData1' ,$plantId, $lineId, $year, $month);
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace App\Filament\Pages;
use Filament\Pages\Page;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
use Filament\Tables\Filters\SelectFilter;
use Illuminate\Support\Facades\DB;
use App\Models\Plant;
use App\Models\RequestQuotation;
use App\Models\RfqTransporterBid;
use Filament\Facades\Filament;
use Filament\Widgets\Widget;
use Illuminate\Support\Facades\Auth;
use Filament\Forms\Components\Section;
use Filament\Forms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
class RfqDashboard extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.rfq-dashboard';
protected static ?string $navigationGroup = 'RFQ Dashboard';
use HasFiltersForm;
public function mount(): void
{
session()->forget(['transport_name']);
session()->forget(['rfq_number']);
$this->filtersForm->fill([
'transport_name' => null,
'rfq_number' => null
]);
}
public function filtersForm(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
// Select::make('plant')
// ->label('Select Plant')
// ->reactive()
// ->options(function (callable $get) {
// $userHas = Filament::auth()->user()->plant_id;
// return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
// })
// ->afterStateUpdated(function ($state,callable $set) {
// session(['selected_plant' => $state]);
// // $set('rfq_number', null);
// session()->forget('rfq_number');
// }),
Select::make('rfq_number')
->label('Select RFQ Number')
->reactive()
->options(function (callable $get) {
return RequestQuotation::orderBy('rfq_number')
->pluck('rfq_number', 'id')
->toArray();
})
->afterStateUpdated(function ($state, callable $set) {
session(['rfq_id' => $state]);
$set('transport_name', null);
session()->forget('transport_name');
}),
Select::make('transport_name')
->label('User name')
->reactive()
->options(function (callable $get) {
$rfqId = $get('rfq_number');
if (!$rfqId) {
return [];
}
$user = Filament::auth()->user();
if ($user->hasRole(['Super Admin', 'Rfq Supervisor'])) {
return RfqTransporterBid::query()
->where('request_quotation_id', $rfqId)
->whereNotNull('transporter_name')
->distinct()
->pluck('transporter_name', 'transporter_name')
->toArray();
}
return RfqTransporterBid::query()
->where('request_quotation_id', $rfqId)
->where('transporter_name', $user->name)
->distinct()
->pluck('transporter_name', 'transporter_name')
->toArray();
})
->afterStateUpdated(function ($state, callable $set) {
session(['transport_name' => $state]);
}),
// Select::make('transport_name')
// ->label('User name')
// ->reactive()
// ->options(function () {
// $user = Filament::auth()->user();
// if ($user->hasRole(['Super Admin', 'Rfq Supervisor'])) {
// return RfqTransporterBid::query()
// ->whereNotNull('transporter_name')
// ->distinct()
// ->pluck('transporter_name', 'transporter_name')
// ->toArray();
// }
// return RfqTransporterBid::query()
// ->where('transporter_name', $user->name)
// ->distinct()
// ->pluck('transporter_name', 'transporter_name')
// ->toArray();
// })
// ->afterStateUpdated(function ($state, callable $set) {
// session(['transport_name' => $state]);
// $set('rfq_number', null);
// session()->forget('rfq_number');
// }),
// Select::make('rfq_number')
// ->label('Select RFQ Number')
// ->reactive()
// ->options(function (callable $get) {
// $transportName = $get('transport_name');
// if (!$transportName) {
// return [];
// }
// return RequestQuotation::where('transporter_name', $transportName)
// ->pluck('rfq_number', 'rfq_number')
// ->toArray();
// })
// ->afterStateUpdated(function ($state) {
// session(['rfq_number' => $state]);
// }),
])
->columns(2),
]);
}
public static function canAccess(): bool
{
return Auth::check() && Auth::user()->can('view rfq dashboard');
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace App\Filament\Pages;
use App\Models\RequestQuotation;
use Filament\Pages\Page;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
use Illuminate\Support\Facades\Auth;
class RfqOverview extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.rfq-overview';
protected static ?string $navigationGroup = 'RFQ Dashboard';
use HasFiltersForm;
public function mount(): void
{
session()->forget(['rfq_id']);
$this->filtersForm->fill([
'rfq_id' => null
]);
}
public function filtersForm(Form $form): Form
{
return $form
->statePath('filters')
->schema([
Section::make('')
->schema([
Select::make('rfq_number')
->label('Select RFQ Number')
->reactive()
->options(function (callable $get) {
return RequestQuotation::orderBy('rfq_number')
->pluck('rfq_number', 'id')
->toArray();
})
->afterStateUpdated(function ($state, callable $set) {
session(['rfq_id' => $state]);
}),
])
->columns(1),
]);
}
public static function canAccess(): bool
{
return Auth::check() && Auth::user()->can('view rfq overview dashboard');
}
}

View File

@@ -0,0 +1,240 @@
<?php
namespace App\Filament\Pages;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\Plant;
use App\Models\StickerDetail;
use App\Models\StickerStructureDetail;
use App\Services\StickerPdfService;
use Filament\Facades\Filament;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\ViewField;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Notifications\Notification;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
use Filament\Pages\Page;
use Illuminate\Support\Facades\Auth;
class StickerStructurePreviewPage extends Page
{
use HasFiltersForm;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.sticker-structure-preview-page';
protected static ?string $navigationGroup = 'Customized Sticker Printing';
public $stickerId;
public $plantId;
public $itemId;
public ?string $pdfPreview = null;
// public array $filters = [];
public function mount(): void
{
session()->forget(['stick_id', 'selected_plant', 'selected_item']);
$this->form->fill([
'sticker_id' => null,
'plant' => null,
'item' => null,
]);
}
public function form(Form $form): Form
{
return $form
->statePath('filters') // Store form state in 'filters'
->schema([
Section::make('')
->schema([
Select::make('sticker_id')
->label('Sticker ID')
->nullable()
->options(function (callable $get) {
return StickerStructureDetail::orderByDesc('id')->pluck('sticker_id', 'sticker_id')->toArray();
})
->afterStateUpdated(callback: function ($state, callable $set) {
session(['stick_id' => $state]);
$set('plant', null);
$set('item', null);
$this->pdfPreview = null;
})
->searchable()
->reactive()
->required(),
Select::make('plant')
->label('Select Plant')
->reactive()
// ->options(Plant::pluck('name', 'id'))
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
})
->afterStateUpdated(function ($state, callable $set) {
session(['stick_id' => $state]);
session(['selected_plant' => $state]);
$set('item', null);
session()->forget('item');
$this->pdfPreview = null;
}),
Select::make('item')
->label('Search by Item Code')
->nullable()
->options(function (callable $get) {
$plant = $get('plant');
return $plant ? ItemCharacteristic::where('plant_id', $plant)->with('item')->get()->pluck('item.code', 'id')->toArray() : []; // ->orderBy('plant_id')
})
->afterStateUpdated(function ($state, callable $set) {
session(['stick_id' => $state]);
session(['selected_plant' => $state]);
session(['selected_item' => $state]);
$this->pdfPreview = null;
// $set('item_id', null);
// session()->forget('item');
})
->searchable()
->reactive(),
// ViewField::make('generate_template')
// ->view('fields.generate-template-preview')
// ->reactive()
// // ->key(fn ($get) => 'generate-template' . ($get('sticker_id_live') ?? 'empty'))
// ->key(fn (Get $get) => 'generate-template-'.
// ($get('sticker_id') ?? 'empty').'-'.
// ($get('plant') ?? 'empty').'-'.
// ($get('item_characteristic_id') ?? 'empty')
// )
// // ->viewData(fn (Get $get) => [
// // 'sticker_id' => $get('sticker_id_live') ?? 'empty',
// // ]),
// ->viewData(fn (Get $get) => [
// 'sticker_id' => $get('sticker_id') ?? 'empty',
// 'plant_id' => $get('plant') ?? 'empty',
// 'item_characteristic_id' => $get('item') ?? 'empty',
// ])
// ->hidden(fn (callable $get) => ($get('sticker_id') == null || $get('sticker_id') == '0' || empty($get('sticker_id'))) || (($get('plant') != null || $get('plant') != '') &&
// ($get('item') == null || $get('item') == '' || empty($get('item'))))),
])
->columns(3),
]);
}
public function showPreview()
{
$state = $this->form->getState();
$stickerId = trim($state['sticker_id'] ?? '') ?: null;
// $stickerId = $this->form->getState()['sticker_id'];
// $stickerId = trim($stickerId) ?? null;
$this->stickerId = $stickerId;
$plantId = trim($state['plant'] ?? '') ?: null;
// $plantId = $this->form->getState()['plant'];
// $plantId = trim($plantId) ?? null;
$this->plantId = $plantId;
$itemId = trim($state['item'] ?? '') ?: null;
// $itemId = $this->form->getState()['item'];
// $itemId = trim($itemId) ?? null;
$this->itemId = $itemId;
$this->pdfPreview = null;
// $operatorName = Filament::auth()->user()->name;
if (! $stickerId) {
Notification::make()->title('Please select a Sticker ID first!')->danger()->duration(2000)->send();
$this->form->fill([
'sticker_id' => $stickerId ?? null,
'plant' => $plantId ?? null,
'item' => $itemId ?? null,
]);
return;
} elseif ($plantId && ! $itemId) {
Notification::make()->title('Please select an Item Code!')->danger()->duration(2000)->send();
$this->form->fill([
'sticker_id' => $stickerId,
'plant' => $plantId ?? null,
'item' => $itemId ?? null,
]);
return;
} elseif ($stickerId && $plantId && $itemId != null && $itemId != '') {
$itemCharacteristic = $itemId ? ItemCharacteristic::find($itemId) : null;
$structure = StickerStructureDetail::where('sticker_id', $stickerId)->first();
if (! $structure) {
Notification::make()->title('Sticker structure not found!')->danger()->send();
return;
}
$dynamicElements = StickerDetail::where('sticker_structure_detail_id', $structure->id)->get();
try {
$stickerPdfService = new StickerPdfService;
$this->pdfPreview = $stickerPdfService->generateStickerItem($stickerId, $dynamicElements, $itemCharacteristic);
Notification::make()
->title('Sticker Preview Generated!')
->success()
->duration(2000)
->send();
} catch (\Exception $e) {
Notification::make()
->title('Error generating sticker preview!')
->body($e->getMessage())
->danger()
->send();
}
} else {
$elements = StickerStructureDetail::where('sticker_id', $stickerId)->first();
try {
$stickerPdfService = new StickerPdfService;
$this->pdfPreview = $stickerPdfService->generateSticker($stickerId, $elements->toArray());
Notification::make()
->title('Sticker Preview Generated!')
->success()
->duration(2000)
->send();
} catch (\Exception $e) {
Notification::make()
->title('Error generating sticker preview!')
->body($e->getMessage())
->danger()
->send();
}
}
}
public static function getNavigationLabel(): string
{
return 'Sticker Structure Preview';
}
public function getHeading(): string
{
return 'Sticker Structure Preview';
}
public static function canAccess(): bool
{
return Auth::check() && Auth::user()->can('view sticker structure preview');
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Filament\Pages;
use Filament\Pages\Page;
class Welcome extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.welcome';
public function getHeading(): string
{
return '';
}
}

View File

@@ -0,0 +1,217 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\EmployeeMasterExporter;
use App\Filament\Imports\EmployeeMasterImporter;
use App\Filament\Resources\EmployeeMasterResource\Pages;
use App\Filament\Resources\EmployeeMasterResource\RelationManagers;
use App\Models\EmployeeMaster;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Illuminate\Validation\Rule;
class EmployeeMasterResource extends Resource
{
protected static ?string $model = EmployeeMaster::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->relationship('plant', 'name')
->required(),
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->reactive()
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^a-zA-Z\s]/g, "")',
]),
Forms\Components\TextInput::make('code')
->label('ID')
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^a-zA-Z0-9]/g, "")',])
->required()
->unique(
table: 'employee_masters',
column: 'code',
ignoreRecord: true
)
->validationMessages([
'unique' => 'Duplicate employee code already exists.',
]),
Forms\Components\TextInput::make('department')
->label('Department')
->required(),
Forms\Components\TextInput::make('designation')
->label('Designation')
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^a-zA-Z\s]/g, "")',])
->required(),
Forms\Components\TextInput::make('email')
->label('Email')
->email()
->required(),
Forms\Components\TextInput::make('mobile_number')
->label('Mobile Number')
->length(10)
->reactive()
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^0-9]/g, "").slice(0, 10)', // blocks non-numbers + limits to 10 chars
'maxlength' => 10,
])
->required()
->unique(
table: 'employee_masters',
column: 'mobile_number',
ignoreRecord: true
)
->validationMessages([
'unique' => 'Duplicate mobile number already exists.',
]),
Forms\Components\Hidden::make('created_by')
->label('Created by')
->default(Filament::auth()->user()?->name ?? ''),
Forms\Components\Hidden::make('updated_by')
->label('Updated by')
->default(Filament::auth()->user()?->name ?? ''),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
})
->alignCenter(),
Tables\Columns\TextColumn::make('plant.name')
->numeric()
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('name')
->label('Name')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('code')
->label('Employee ID')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('department')
->label('Department')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('designation')
->label('Designation')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('email')
->label('Email')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('mobile_number')
->label('Mobile Number')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
Tables\Columns\TextColumn::make('created_by')
->label('Created by')
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated by')
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->importer(EmployeeMasterImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import employee master');
}),
ExportAction::make()
->exporter(EmployeeMasterExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export employee master');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListEmployeeMasters::route('/'),
'create' => Pages\CreateEmployeeMaster::route('/create'),
'view' => Pages\ViewEmployeeMaster::route('/{record}'),
'edit' => Pages\EditEmployeeMaster::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\EmployeeMasterResource\Pages;
use App\Filament\Resources\EmployeeMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateEmployeeMaster extends CreateRecord
{
protected static string $resource = EmployeeMasterResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\EmployeeMasterResource\Pages;
use App\Filament\Resources\EmployeeMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditEmployeeMaster extends EditRecord
{
protected static string $resource = EmployeeMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\EmployeeMasterResource\Pages;
use App\Filament\Resources\EmployeeMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListEmployeeMasters extends ListRecords
{
protected static string $resource = EmployeeMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\EmployeeMasterResource\Pages;
use App\Filament\Resources\EmployeeMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewEmployeeMaster extends ViewRecord
{
protected static string $resource = EmployeeMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -10,6 +10,7 @@ use App\Models\InvoiceValidation;
use App\Models\Item;
use App\Models\Plant;
use App\Models\StickerMaster;
use App\Notifications\PushAlertNotification;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Pages\Concerns\ExposesTableToWidgets;
@@ -136,6 +137,10 @@ class CreateInvoiceValidation extends CreateRecord
->send();
$this->dispatch('playNotificationSound');
$user1 = Filament::auth()->user();
$user1->notify(new PushAlertNotification());
$this->form->fill([
'plant_id' => $plantId,
'invoice_number' => $invoiceNumber,
@@ -2285,6 +2290,7 @@ class CreateInvoiceValidation extends CreateRecord
->danger()
->seconds(3)
->send();
$this->dispatch('playWarnSound');
$this->form->fill([

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@ use AlperenErsoy\FilamentExport\Actions\FilamentExportBulkAction;
use App\Filament\Exports\ProductionPlanExporter;
use App\Filament\Imports\ProductionPlanImporter;
use App\Filament\Resources\ProductionPlanResource\Pages;
use App\Filament\Resources\ProductionPlanResource\RelationManagers;
use App\Models\Block;
use App\Models\Item;
use App\Models\Line;
use App\Models\Plant;
use App\Models\ProductionPlan;
@@ -16,19 +16,18 @@ use Carbon\Carbon;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Filters\Filter;
use Illuminate\Support\Facades\Request;
class ProductionPlanResource extends Resource
{
@@ -55,22 +54,22 @@ class ProductionPlanResource extends Resource
->reactive()
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::orderBy('code')->pluck('name', 'id')->toArray();
})
->default(function () {
return optional(ProductionPlan::latest()->first())->plant_id;
})
->disabled(fn (Get $get) => !empty($get('id')))
->disabled(fn (Get $get) => ! empty($get('id')))
// ->afterStateUpdated(fn ($set) => $set('block_name', null))
->afterStateUpdated(function ($state, callable $set, callable $get) {
$plantId = $get('plant_id');
$set('block_name', null);
if (!$plantId) {
if (! $plantId) {
$set('ppPlantError', 'Please select a plant first.');
return;
}
else
{
} else {
$set('ppPlantError', null);
}
})
@@ -79,102 +78,6 @@ class ProductionPlanResource extends Resource
])
->hint(fn ($get) => $get('ppPlantError') ? $get('ppPlantError') : null)
->hintColor('danger'),
Forms\Components\Select::make('block_name')
->required()
// ->nullable()
->label('Block')
->options(function (callable $get) {
if (!$get('plant_id')) {
return [];
}
return Block::where('plant_id', $get('plant_id'))
->pluck('name', 'id')
->toArray();
})
->reactive()
->default(function () {
$latestShiftId = optional(ProductionPlan::latest()->first())->shift_id;
return optional(Shift::where('id', $latestShiftId)->first())->block_id;
})
//->afterStateUpdated(fn ($set) => $set('shift_id', null))
->afterStateUpdated(function ($state, callable $set, callable $get) {
if($get('id'))
{
$getShift = ProductionPlan::where('id', $get('id'))->first();
$getBlock = Shift::where('id', $getShift->shift_id)->first();
if($getBlock->block_id)
{
$set('block_name', $getBlock->block_id);
$set('ppBlockError', null);
}
}
$blockId = $get('block_name');
$set('shift_id', null);
if (!$blockId) {
$set('ppBlockError', 'Please select a block first.');
return;
}
else
{
$set('ppBlockError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('ppBlockError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('ppBlockError') ? $get('ppBlockError') : null)
->hintColor('danger'),
Forms\Components\Select::make('shift_id')
->relationship('shift', 'name')
->required()
// ->nullable()
->autofocus(true)
->options(function (callable $get) {
if (!$get('plant_id') || !$get('block_name')) {
return [];
}
return Shift::where('plant_id', $get('plant_id'))
->where('block_id', $get('block_name'))
->pluck('name', 'id')
->toArray();
})
->reactive()
->default(function () {
return optional(ProductionPlan::latest()->first())->shift_id;
})
// ->afterStateUpdated(fn ($set) => $set('line_id', null))
->afterStateUpdated(function ($state, callable $set, callable $get) {
if($get('id'))
{
$getShift = ProductionPlan::where('id', $get('id'))->first();
if($getShift->shift_id)
{
$set('shift_id', $getShift->shift_id);
$set('ppShiftError', null);
}
}
$curShiftId = $get('shift_id');
$set('line_id', null);
if (!$curShiftId) {
$set('ppShiftError', 'Please select a shift first.');
return;
}
else
{
$set('ppShiftError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('ppShiftError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('ppShiftError') ? $get('ppShiftError') : null)
->hintColor('danger'),
Forms\Components\Select::make('line_id')
->relationship('line', 'name')
->required()
@@ -185,7 +88,7 @@ class ProductionPlanResource extends Resource
// ->toArray() // Convert collection to array
// )
->options(function (callable $get) {
if (!$get('plant_id') || !$get('block_name') || !$get('shift_id')) {
if (! $get('plant_id')) {
return [];
}
@@ -197,248 +100,257 @@ class ProductionPlanResource extends Resource
// ->default(function () {
// return optional(ProductionPlan::latest()->first())->line_id;
// })
// ->afterStateUpdated(function ($state, callable $set, callable $get) {
// if ($get('id')) {
// $getShift = ProductionPlan::where('id', $get('id'))->first();
// if ($getShift->line_id) {
// $set('line_id', $getShift->line_id);
// $set('ppLineError', null);
// }
// } else {
// $currentDT = Carbon::now()->toDateTimeString();
// $set('created_at', $currentDT);
// $set('update_date', null);
// }
// $lineId = $get('line_id');
// // $set('plan_quantity', null);
// if (! $lineId) {
// $set('ppLineError', 'Please select a line first.');
// return;
// } else {
// $isUpdate = ! empty($get('id'));
// if (! $isUpdate) {
// $exists = ProductionPlan::where('plant_id', $get('plant_id'))
// ->where('shift_id', $get('shift_id'))
// ->where('line_id', $get('line_id'))
// ->whereDate('created_at', today())
// ->latest()
// ->exists();
// if ($exists) {
// $set('line_id', null);
// $set('ppLineError', 'Production plan already updated.');
// return;
// } else {
// $existShifts = ProductionPlan::where('plant_id', $get('plant_id'))
// ->where('shift_id', $get('shift_id'))
// ->where('line_id', $get('line_id'))
// ->whereDate('created_at', Carbon::yesterday())
// ->latest()
// ->exists();
// if ($existShifts) { // if ($existShifts->count() > 0)
// // $currentDate = date('Y-m-d');
// $yesterday = date('Y-m-d', strtotime('-1 days'));
// $shiftId = Shift::where('id', $get('shift_id'))
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $yesterday.' '.$shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt." + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
// // echo "Choosed a valid shift...";
// $set('line_id', null);
// $set('ppLineError', 'Production plan already updated.');
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// return;
// } else {
// $currentDate = date('Y-m-d');
// $shiftId = Shift::where('id', $get('shift_id'))
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $currentDate.' '.$shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt." + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if (! ($currentDateTime >= $from_dt && $currentDateTime < $to_dt)) {
// // echo "Choosed a valid shift...";
// $set('line_id', null);
// $set('ppLineError', 'Choosed a invalid shift.');
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// return;
// }
// }
// $set('ppLineError', null);
// return;
// } else {
// // $currentDate = date('Y-m-d');
// $yesterday = date('Y-m-d', strtotime('-1 days'));
// $shiftId = Shift::where('id', $get('shift_id'))
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $yesterday.' '.$shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt." + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
// // echo "Choosed a valid shift...";
// // here i'm updating created as yesterday
// $set('created_at', $from_dt);
// $set('update_date', '1');
// $set('ppLineError', null);
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// return;
// } else {
// $currentDate = date('Y-m-d');
// $shiftId = Shift::where('id', $get('shift_id'))
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $currentDate.' '.$shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt." + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if (! ($currentDateTime >= $from_dt && $currentDateTime < $to_dt)) {
// // echo "Choosed a valid shift...";
// $set('line_id', null);
// $set('ppLineError', 'Choosed a invalid shift.');
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// return;
// }
// }
// $set('ppLineError', null);
// return;
// }
// // $exists = ProductionPlan::where('plant_id', $get('plant_id'))
// // //->where('shift_id', $get('shift_id'))
// // ->where('line_id', $get('line_id'))
// // ->whereDate('created_at', today())
// // ->latest() // Orders by created_at DESC
// // ->first();
// // if ($exists)
// // {
// // $existingShifts = ProductionPlan::where('plant_id', $get('plant_id'))
// // //->where('shift_id', $get('shift_id'))
// // ->where('line_id', $get('line_id'))
// // // ->whereDate('created_at', today())
// // ->whereDate('created_at', today())
// // ->get();
// // foreach ($existingShifts as $shift) {
// // $curShiftId = $shift->shift_id;
// // $currentDate = date('Y-m-d');
// // $shiftId = \App\Models\Shift::where('id', $curShiftId)
// // ->first();
// // [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// // $hRs = (int) $hRs;
// // // $miNs = (int) $miNs;-*/
// // $totalMinutes = $hRs * 60 + $miNs;
// // $from_dt = $currentDate . ' ' . $shiftId->start_time;
// // $to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
// // $currentDateTime = date('Y-m-d H:i:s');
// // // Check if current date time is within the range
// // if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
// // //echo "Choosed a valid shift...";
// // // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// // $set('line_id', null);
// // $set('ppLineError', 'Production plan already updated.');
// // return;
// // }
// // // else {
// // // $set('ppLineError', 'Choosed a invalid shift...');
// // // return;
// // // }
// // }
// // $set('ppLineError', null);
// // return;
// // }
// }
// }
// $set('ppLineError', null);
// }
// })
->afterStateUpdated(function ($state, callable $set, callable $get) {
if($get('id'))
{
$getShift = ProductionPlan::where('id', $get('id'))->first();
if($getShift->line_id)
{
$set('line_id', $getShift->line_id);
$set('ppLineError', null);
}
}
else
{
$currentDT = Carbon::now()->toDateTimeString();
$set('created_at', $currentDT);
$set('update_date', null);
}
$lineId = $get('line_id');
// $set('plan_quantity', null);
if (!$lineId) {
$set('ppLineError', 'Please select a line first.');
return;
}
else
{
$isUpdate = !empty($get('id'));
if (!$isUpdate)
{
$exists = ProductionPlan::where('plant_id', $get('plant_id'))
->where('shift_id', $get('shift_id'))
->where('line_id', $get('line_id'))
->whereDate('created_at', today())
->latest()
->exists();
if ($exists)
{
$set('line_id', null);
$set('ppLineError', 'Production plan already updated.');
return;
}
else
{
$existShifts = ProductionPlan::where('plant_id', $get('plant_id'))
->where('shift_id', $get('shift_id'))
->where('line_id', $get('line_id'))
->whereDate('created_at', Carbon::yesterday())
->latest()
->exists();
if ($existShifts) //if ($existShifts->count() > 0)
{
//$currentDate = date('Y-m-d');
$yesterday = date('Y-m-d', strtotime('-1 days'));
$shiftId = Shift::where('id', $get('shift_id'))
->first();
[$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
$hRs = (int) $hRs;
// $miNs = (int) $miNs;-*/
$totalMinutes = $hRs * 60 + $miNs;
$from_dt = $yesterday . ' ' . $shiftId->start_time;
$to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
$currentDateTime = date('Y-m-d H:i:s');
// Check if current date time is within the range
if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
//echo "Choosed a valid shift...";
$set('line_id', null);
$set('ppLineError', 'Production plan already updated.');
// $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
return;
}
else
{
$currentDate = date('Y-m-d');
$shiftId = Shift::where('id', $get('shift_id'))
->first();
[$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
$hRs = (int) $hRs;
// $miNs = (int) $miNs;-*/
$totalMinutes = $hRs * 60 + $miNs;
$from_dt = $currentDate . ' ' . $shiftId->start_time;
$to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
$currentDateTime = date('Y-m-d H:i:s');
// Check if current date time is within the range
if (!($currentDateTime >= $from_dt && $currentDateTime < $to_dt)) {
//echo "Choosed a valid shift...";
$set('line_id', null);
$set('ppLineError', 'Choosed a invalid shift.');
// $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
return;
}
}
$set('ppLineError', null);
return;
}
else
{
//$currentDate = date('Y-m-d');
$yesterday = date('Y-m-d', strtotime('-1 days'));
$shiftId = Shift::where('id', $get('shift_id'))
->first();
[$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
$hRs = (int) $hRs;
// $miNs = (int) $miNs;-*/
$totalMinutes = $hRs * 60 + $miNs;
$from_dt = $yesterday . ' ' . $shiftId->start_time;
$to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
$currentDateTime = date('Y-m-d H:i:s');
// Check if current date time is within the range
if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
//echo "Choosed a valid shift...";
// here i'm updating created as yesterday
$set('created_at', $from_dt);
$set('update_date', '1');
$set('ppLineError', null);
// $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
return;
}
else
{
$currentDate = date('Y-m-d');
$shiftId = Shift::where('id', $get('shift_id'))
->first();
[$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
$hRs = (int) $hRs;
// $miNs = (int) $miNs;-*/
$totalMinutes = $hRs * 60 + $miNs;
$from_dt = $currentDate . ' ' . $shiftId->start_time;
$to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
$currentDateTime = date('Y-m-d H:i:s');
// Check if current date time is within the range
if (!($currentDateTime >= $from_dt && $currentDateTime < $to_dt)) {
//echo "Choosed a valid shift...";
$set('line_id', null);
$set('ppLineError', 'Choosed a invalid shift.');
// $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
return;
}
}
$set('ppLineError', null);
return;
}
// $exists = ProductionPlan::where('plant_id', $get('plant_id'))
// //->where('shift_id', $get('shift_id'))
// ->where('line_id', $get('line_id'))
// ->whereDate('created_at', today())
// ->latest() // Orders by created_at DESC
// ->first();
// if ($exists)
// {
// $existingShifts = ProductionPlan::where('plant_id', $get('plant_id'))
// //->where('shift_id', $get('shift_id'))
// ->where('line_id', $get('line_id'))
// // ->whereDate('created_at', today())
// ->whereDate('created_at', today())
// ->get();
// foreach ($existingShifts as $shift) {
// $curShiftId = $shift->shift_id;
// $currentDate = date('Y-m-d');
// $shiftId = \App\Models\Shift::where('id', $curShiftId)
// ->first();
// [$hRs, $miNs] = explode('.', $shiftId->duration) + [0, 0];
// $hRs = (int) $hRs;
// // $miNs = (int) $miNs;-*/
// $totalMinutes = $hRs * 60 + $miNs;
// $from_dt = $currentDate . ' ' . $shiftId->start_time;
// $to_dt = date('Y-m-d H:i:s', strtotime($from_dt . " + $totalMinutes minutes"));
// $currentDateTime = date('Y-m-d H:i:s');
// // Check if current date time is within the range
// if ($currentDateTime >= $from_dt && $currentDateTime < $to_dt) {
// //echo "Choosed a valid shift...";
// // $set('ppLineError', 'Valid (From: '.$from_dt.', To: '.$to_dt.')');
// $set('line_id', null);
// $set('ppLineError', 'Production plan already updated.');
// return;
// }
// // else {
// // $set('ppLineError', 'Choosed a invalid shift...');
// // return;
// // }
// }
// $set('ppLineError', null);
// return;
// }
}
}
$set('ppLineError', null);
}
$set('item_id', null);
$set('plan_quantity', null);
})
->extraAttributes(fn ($get) => [
'class' => $get('ppLineError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('ppLineError') ? $get('ppLineError') : null)
->hintColor('danger'),
Forms\Components\Select::make('item_id')
->label('Item')
->reactive()
->searchable()
->required()
->options(function (callable $get) {
if (! $get('plant_id')) {
return [];
}
return Item::where('plant_id', $get('plant_id'))
->pluck('code', 'id')
->toArray();
}),
Forms\Components\TextInput::make('plan_quantity')
->required()
->integer()
@@ -449,21 +361,18 @@ class ProductionPlanResource extends Resource
->afterStateUpdated(function ($state, callable $set, callable $get) {
$planQuan = $get('plan_quantity');
if(!$get('update_date') )
{
if(!$get('id'))
{
if (! $get('update_date')) {
if (! $get('id')) {
$currentDT = Carbon::now()->toDateTimeString();
$set('created_at', $currentDT);
}
}
if (!$planQuan) {
if (! $planQuan) {
$set('ppPlanQuanError', 'Scan the valid plan quantity.');
return;
}
else
{
} else {
$set('ppPlanQuanError', null);
}
})
@@ -472,29 +381,19 @@ class ProductionPlanResource extends Resource
])
->hint(fn ($get) => $get('ppPlanQuanError') ? $get('ppPlanQuanError') : null)
->hintColor('danger'),
Forms\Components\TextInput::make('production_quantity')
->required()
->integer()
->label('Production Quantity')
->readOnly(fn (callable $get) => !$get('id'))
->default(0),
// Forms\Components\TextInput::make('production_quantity')
// ->required()
// ->integer()
// ->label('Production Quantity')
// ->readOnly(fn (callable $get) => ! $get('id'))
// ->default(0),
Forms\Components\TextInput::make('id')
->hidden()
->readOnly(),
Forms\Components\TextInput::make('update_date')
->hidden()
->reactive()
->readOnly(),
Forms\Components\DateTimePicker::make('created_at')
->label('Created DateTime')
->hidden()
->reactive()
->required()
->readOnly(),
Forms\Components\Hidden::make('operator_id')
->default(Filament::auth()->user()->name),
])
->columns(2),
])
->columns(4),
]);
}
@@ -529,34 +428,55 @@ class ProductionPlanResource extends Resource
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('line.name')
->label('Plant')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('item.code')
->label('Item')
->alignCenter()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('plan_quantity')
->label('Plan Quantity')
->alignCenter()
->numeric()
->sortable(),
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('working_days')
->label('Working Days')
->alignCenter()
->numeric()
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('production_quantity')
->label('Production Quantity')
->alignCenter()
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('line.name')
->label('Line')
->alignCenter()
->sortable(),// ->searchable(),
Tables\Columns\TextColumn::make('shift.block.name')
->label('Block')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('shift.name')
->label('Shift')
->alignCenter()
->sortable(),// ->searchable(),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),// ->searchable(),
->sortable()
->searchable(),
// Tables\Columns\TextColumn::make('line.name')
// ->label('Line')
// ->alignCenter()
// ->sortable(), // ->searchable(),
// Tables\Columns\TextColumn::make('shift.block.name')
// ->label('Block')
// ->alignCenter()
// ->sortable(),
// Tables\Columns\TextColumn::make('shift.name')
// ->label('Shift')
// ->alignCenter()
// ->sortable(), // ->searchable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
@@ -584,7 +504,7 @@ class ProductionPlanResource extends Resource
Filter::make('advanced_filters')
->label('Advanced Filters')
->form([
//plant
// plant
Select::make('Plant')
->label('Select Plant')
->nullable()
@@ -593,7 +513,8 @@ class ProductionPlanResource extends Resource
// })
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::orderBy('code')->pluck('name', 'id')->toArray();
})
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
@@ -602,31 +523,33 @@ class ProductionPlanResource extends Resource
$set('Shift', null);
}),
//line
// line
Select::make('Line')
->label('Select line')
->nullable()
->options(function (callable $get) {
$plantId = $get('Plant');
if (!$plantId ) {
if (! $plantId) {
return [];
}
return Line::where('plant_id', $plantId)
->pluck('name', 'id');
->pluck('name', 'id');
})
->reactive(),
//block
// block
Select::make('Block')
->label('Select Block')
->nullable()
->options(function (callable $get) {
$plantId = $get('Plant');
if (!$plantId ) {
if (! $plantId) {
return [];
}
return Block::where('plant_id', $get('Plant'))->pluck('name', 'id');
})
->reactive()
@@ -634,7 +557,7 @@ class ProductionPlanResource extends Resource
$set('Shift', null);
}),
//shift
// shift
Select::make('Shift')
->label('Select Shift')
->nullable()
@@ -642,7 +565,7 @@ class ProductionPlanResource extends Resource
$plantId = $get('Plant');
$blockId = $get('Block');
if (!$plantId || !$blockId) {
if (! $plantId || ! $blockId) {
return []; // Return empty if plant or block is not selected
}
@@ -669,52 +592,66 @@ class ProductionPlanResource extends Resource
return $query->whereRaw('1 = 0');
}
if ($plant = $data['Plant'] ?? null) {
$query->where('plant_id', $plant);
if (! empty($data['Plant'])) {// if ($plant = $data['Plant'] ?? null) {
$query->where('plant_id', $data['Plant']);
} else {
$userHas = Filament::auth()->user()->plant_id;
if ($userHas && strlen($userHas) > 0) {
return $query->whereRaw('1 = 0');
}
}
if ($shift = $data['Shift'] ?? null) {
$query->where('shift_id', $shift);
if (! empty($data['Shift'])) {// if ($shift = $data['Shift'] ?? null) {
$query->where('shift_id', $data['Shift']);
}
if ($line = $data['Line'] ?? null) {
$query->where('line_id', $line);
if (! empty($data['Line'])) {// if ($line = $data['Line'] ?? null) {
$query->where('line_id', $data['Line']);
}
if ($from = $data['created_from'] ?? null) {
$query->where('created_at', '>=', $from);
if (! empty($data['created_from'])) {// if ($from = $data['created_from'] ?? null) {
$query->where('created_at', '>=', $data['created_from']);
}
if ($to = $data['created_to'] ?? null) {
$query->where('created_at', '<=', $to);
if (! empty($data['created_to'])) {// if ($to = $data['created_to'] ?? null) {
$query->where('created_at', '<=', $data['created_to']);
}
return $query;
})
->indicateUsing(function (array $data) {
$indicators = [];
if (!empty($data['Plant'])) {
$indicators[] = 'Plant: ' . Plant::where('id', $data['Plant'])->value('name');
if (! empty($data['Plant'])) {
$indicators[] = 'Plant: '.Plant::where('id', $data['Plant'])->value('name');
} else {
$userHas = Filament::auth()->user()->plant_id;
if ($userHas && strlen($userHas) > 0) {
return 'Plant: Choose plant to filter records.';
}
}
if (!empty($data['Shift'])) {
$indicators[] = 'Shift: ' . Shift::where('id', $data['Shift'])->value('name');
if (! empty($data['Shift'])) {
$indicators[] = 'Shift: '.Shift::where('id', $data['Shift'])->value('name');
}
if (!empty($data['Line'])) {
$indicators[] = 'Line: ' . Line::where('id', $data['Line'])->value('name');
if (! empty($data['Line'])) {
$indicators[] = 'Line: '.Line::where('id', $data['Line'])->value('name');
}
if (!empty($data['created_from'])) {
$indicators[] = 'From: ' . $data['created_from'];
if (! empty($data['created_from'])) {
$indicators[] = 'From: '.$data['created_from'];
}
if (!empty($data['created_to'])) {
$indicators[] = 'To: ' . $data['created_to'];
if (! empty($data['created_to'])) {
$indicators[] = 'To: '.$data['created_to'];
}
return $indicators;
})
}),
])
->filtersFormMaxHeight('280px')
->actions([
@@ -726,7 +663,7 @@ class ProductionPlanResource extends Resource
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
FilamentExportBulkAction::make('export')
FilamentExportBulkAction::make('export'),
]),
])
->headerActions([
@@ -734,14 +671,14 @@ class ProductionPlanResource extends Resource
->label('Import Production Plans')
->color('warning')
->importer(ProductionPlanImporter::class)
->visible(function() {
->visible(function () {
return Filament::auth()->user()->can('view import production plan');
}),
ExportAction::make()
->label('Export Production Plans')
->color('warning')
->exporter(ProductionPlanExporter::class)
->visible(function() {
->visible(function () {
return Filament::auth()->user()->can('view export production plan');
}),
]);

View File

@@ -0,0 +1,295 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\RequestQuotationExporter;
use App\Filament\Imports\RequestQuotationImporter;
use App\Filament\Resources\RequestQuotationResource\Pages;
use App\Filament\Resources\RequestQuotationResource\RelationManagers;
use App\Models\RequestQuotation;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Facades\Auth;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
class RequestQuotationResource extends Resource
{
protected static ?string $model = RequestQuotation::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Request For Quotation';
public static function form(Form $form): Form
{
$canEdit = Auth::user()?->can('edit_transport_fields');
$canEditData = Auth::user()?->can('edit_all_transport_fields');
return $form
->schema([
Forms\Components\TextInput::make('rfq_number')
->label('RFQ Number')
->readOnly()
->required(),
Forms\Components\Select::make('spot_rate_transport_master_id')
->label('Group Name')
->relationship('spotRateTransportMaster', 'group_name')
->required(),
Forms\Components\DateTimePicker::make('rfq_date_time')
->label('RFQ Date Time')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('pickup_address')
->label('PickUp Address')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('delivery_address')
->label('Delivery Address')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('weight')
->label('Weight')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('volumetrice_size_inch')
->label('Volumetrice')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('type_of_vehicle')
->label('Type of Vehicle')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('special_type')
->label('Special Type')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('no_of_vehicle')
->label('No of Vehicle')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('product_name')
->label('Product Name')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('loading_by')
->label('Loading By')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('unloading_by')
->label('Unloading By')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('pick_and_delivery')
->label('Pick and Delivery')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('payment_term')
->label('Payment Term')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\TextInput::make('paid_topay')
->label('Paid Today')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\DateTimePicker::make('require_date_time')
->label('Require Date Time')
->disabled(fn () => !$canEditData)
->required(),
Forms\Components\DateTimePicker::make('rfq_rec_on_or_before')
->label('RFQ Receive On Or Before')
->disabled(fn () => !$canEditData)
->required(),
// Forms\Components\TextInput::make('transporter_name')
// ->label('Transporter Name')
// ->disabled(fn () => !($canEdit || $canEditData)),
// Forms\Components\TextInput::make('total_freight_charge')
// ->label('Total Freight Charge')
// ->disabled(fn () => !($canEdit || $canEditData)),
// Forms\Components\TextInput::make('transit_day')
// ->label('Transit Day')
// ->disabled(fn () => !($canEdit || $canEditData)),
Forms\Components\Hidden::make('created_by')
->label('Created By'),
Forms\Components\Hidden::make('updated_by')
->label('Updated By'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->alignCenter()
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('rfq_number')
->label('RFQ Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('spotRateTransportMaster.group_name')
->label('Group Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('rfq_date_time')
->label('RFQ Date Time')
->alignCenter()
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('pickup_address')
->label('PickUp Address')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('delivery_address')
->label('Delivery Address')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('weight')
->label('Weight')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('volumetrice_size_inch')
->label('Volumetrice Size Inch')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('type_of_vehicle')
->label('Type Of Vehicle')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('product_name')
->label('Product Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('loading_by')
->label('Loading By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('unloading_by')
->label('Unloading By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('unloading_by')
->label('Unloading By')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('pick_and_delivery')
->label('Pick and Delivery')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('payment_term')
->label('Payment Term')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('paid_topay')
->label('Paid Today')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('require_date_time')
->label('Require Date Time')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('rfq_rec_on_or_before')
->label('RFQ Receive On Or Before')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('transporter_name')
->label('Transporter Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('total_freight_charge')
->label('Total Freight Charge')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('transit_day')
->label('Transit Day')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import RequestQuotation')
->color('warning')
->importer(RequestQuotationImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import request quotation');
}),
ExportAction::make()
->label('Export RequestQuotation')
->color('warning')
->exporter(RequestQuotationExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export request quotation');
}),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListRequestQuotations::route('/'),
'create' => Pages\CreateRequestQuotation::route('/create'),
'view' => Pages\ViewRequestQuotation::route('/{record}'),
'edit' => Pages\EditRequestQuotation::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Filament\Resources\RequestQuotationResource\Pages;
use App\Filament\Resources\RequestQuotationResource;
use App\Models\RequestQuotation;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateRequestQuotation extends CreateRecord
{
protected static string $resource = RequestQuotationResource::class;
public function mount(): void
{
parent::mount();
$this->form->fill([
'rfq_number' => $this->generateRfqNumber(),
]);
}
protected function generateRfqNumber(): string
{
$year = now()->year;
$lastRfq = RequestQuotation::whereYear('created_at', $year)
->orderBy('id', 'desc')
->value('rfq_number');
if ($lastRfq) {
$lastNumber = (int) substr($lastRfq, -3);
$nextNumber = str_pad($lastNumber + 1, 3, '0', STR_PAD_LEFT);
} else {
$nextNumber = '001';
}
return "C.R.I-{$year}-{$nextNumber}";
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\RequestQuotationResource\Pages;
use App\Filament\Resources\RequestQuotationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditRequestQuotation extends EditRecord
{
protected static string $resource = RequestQuotationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\RequestQuotationResource\Pages;
use App\Filament\Resources\RequestQuotationResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListRequestQuotations extends ListRecords
{
protected static string $resource = RequestQuotationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\RequestQuotationResource\Pages;
use App\Filament\Resources\RequestQuotationResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewRequestQuotation extends ViewRecord
{
protected static string $resource = RequestQuotationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,345 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\RfqTransporterBidResource\Pages;
use App\Filament\Resources\RfqTransporterBidResource\RelationManagers;
use App\Models\RfqTransporterBid;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Validation\Rule;
class RfqTransporterBidResource extends Resource
{
protected static ?string $model = RfqTransporterBid::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Request For Quotation';
public static function getEloquentQuery(): Builder
{
$user = Filament::auth()->user();
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
])
->when(
! $user->hasAnyRole(['Super Admin', 'TransporterBidSupervisor']),
fn (Builder $query) => $query
->where('transporter_name', $user->name)
->whereNotNull('request_quotation_id')
);
}
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('request_quotation_id')
->label('RFQ Number')
// ->relationship('requestQuotation', 'rfq_number')
->relationship(
'requestQuotation',
'rfq_number',
function (Builder $query) {
$userName = Filament::auth()->user()?->name;
$masterIds = \App\Models\SpotRateTransportMaster::whereRaw(
"user_name::jsonb @> ?",
[json_encode([$userName])]
)
->pluck('id')
->unique()
->toArray();
if (empty($masterIds)) {
$query->whereRaw('1 = 0');
return;
}
$query->whereIn('spot_rate_transport_master_id', $masterIds);
}
)
->reactive()
// ->disabled(fn ($record) => !Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor']))
->disabled(fn ($record) =>
!Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor'])
&& $record
)
->afterStateUpdated(function ($state, callable $set) {
$rfq = \App\Models\RequestQuotation::find($state);
if ($rfq) {
$set('pickup_address', $rfq->pickup_address);
$set('delivery_address', $rfq->delivery_address);
$set('type_of_vehicle', $rfq->type_of_vehicle);
$set('weight', $rfq->weight);
$set('volumetrice_size_inch', $rfq->volumetrice_size_inch);
$set('no_of_vehicle', $rfq->no_of_vehicle);
$set('product_name', $rfq->product_name);
$set('pick_and_delivery', $rfq->pick_and_delivery);
$set('payment_term', $rfq->payment_term);
$set('paid_topay', $rfq->paid_topay);
$set('loading_by', $rfq->loading_by);
$set('unloading_by', $rfq->unloading_by);
$set('special_type', $rfq->special_type);
$set('rfq_date_time', $rfq->rfq_date_time);
$set('require_date_time', $rfq->require_date_time);
$set('rfq_rec_on_or_before', $rfq->rfq_rec_on_or_before);
}
})
->afterStateHydrated(function ($state, callable $set) {
$rfq = \App\Models\RequestQuotation::find($state);
if ($rfq) {
$set('pickup_address', $rfq->pickup_address);
$set('delivery_address', $rfq->delivery_address);
$set('type_of_vehicle', $rfq->type_of_vehicle);
$set('weight', $rfq->weight);
$set('volumetrice_size_inch', $rfq->volumetrice_size_inch);
$set('no_of_vehicle', $rfq->no_of_vehicle);
$set('product_name', $rfq->product_name);
$set('pick_and_delivery', $rfq->pick_and_delivery);
$set('payment_term', $rfq->payment_term);
$set('paid_topay', $rfq->paid_topay);
$set('loading_by', $rfq->loading_by);
$set('unloading_by', $rfq->unloading_by);
$set('special_type', $rfq->special_type);
$set('rfq_date_time', $rfq->rfq_date_time);
$set('require_date_time', $rfq->require_date_time);
$set('rfq_rec_on_or_before', $rfq->rfq_rec_on_or_before);
}
})
->required(),
Forms\Components\Section::make('RFQ Details')
->visible(fn ($get) => $get('request_quotation_id') != null)
->reactive()
->schema([
TextInput::make('pickup_address')->label('Pickup Address')->disabled(),
TextInput::make('delivery_address')->label('Delivery Address')->disabled(),
TextInput::make('type_of_vehicle')->label('Vehicle Type')->disabled(),
TextInput::make('weight')->label('Weight')->disabled(),
TextInput::make('volumetrice_size_inch')->label('Volumetric Size')->disabled(),
TextInput::make('no_of_vehicle')->label('No. of Vehicle')->disabled(),
TextInput::make('product_name')->label('Product Name')->disabled(),
TextInput::make('pick_and_delivery')->label('Pick & Delivery')->disabled(),
TextInput::make('payment_term')->label('Payment Term')->disabled(),
TextInput::make('paid_topay')->label('Paid / To Pay')->disabled(),
TextInput::make('loading_by')->label('Loading By')->disabled(),
TextInput::make('unloading_by')->label('Unloading By')->disabled(),
TextInput::make('special_type')->label('Special Type')->disabled(),
TextInput::make('rfq_date_time')->label('RFQ Created On')->disabled(),
TextInput::make('require_date_time')->label('Required Date')->disabled(),
TextInput::make('rfq_rec_on_or_before')->label('RFQ Received On/Before')->disabled(),
]),
Forms\Components\TextInput::make('transporter_name')
->label('Transporter Name')
->readOnly()
->default(Filament::auth()->user()?->name)
->required()
->rule(function (callable $get) {
return Rule::unique('rfq_transporter_bids', 'transporter_name')
->where('request_quotation_id', $get('request_quotation_id'))
->ignore($get('id'));
}),
Forms\Components\TextInput::make('total_freight_charge')
->label('Total Freight Charge')
->required()
// ->disabled(fn ($record) => $record && $record->created_by != Filament::auth()->user()?->name)
// ->hidden(fn ($record) => !Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor']) && $record->transporter_name != Filament::auth()->user()?->name),
->hidden(fn ($record) =>
!Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor'])
&& ($record && $record->transporter_name != Filament::auth()->user()?->name) // Ensure $record is not null before checking transporter_name
),
Forms\Components\TextInput::make('transit_day')
->label('Transit Day')
->required()
// ->disabled(fn ($record) => $record && $record->created_by != Filament::auth()->user()?->name),
// ->hidden(fn ($record) => !Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor']) && $record->transporter_name != Filament::auth()->user()?->name),
->hidden(fn ($record) =>
!Filament::auth()->user()?->hasAnyRole(['Super Admin', 'TransporterBidSupervisor'])
&& ($record && $record->transporter_name != Filament::auth()->user()?->name) // Ensure $record is not null before checking transporter_name
),
Forms\Components\Hidden::make('created_by')
->label('Created By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->label('Updated By')
->default(Filament::auth()->user()?->name),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->alignCenter()
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('requestQuotation.rfq_number')
->label('RFQ Number')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.pickup_address')
->label('PickUp Address')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.delivery_address')
->label('Delivery Address')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.type_of_vehicle')
->label('Type Of Vehicle')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.weight')
->label('Weight')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.volumetrice_size_inch')
->label('Volumetrice Size Inch')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.no_of_vehicle')
->label('No Of Vehicle')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.product_name')
->label('Product Name')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.pick_and_delivery')
->label('Pick And Delivery')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.payment_term')
->label('Payment Term')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.paid_topay')
->label('Paid Today')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.loading_by')
->label('Loading By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.unloading_by')
->label('Unloading By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.special_type')
->label('Special Type')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.rfq_date_time')
->label('RFQ DateTime')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.require_date_time')
->label('RFQ Require DateTime')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('requestQuotation.rfq_rec_on_or_before')
->label('RFQ Rec On Or Before')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('created_by')
->label('Created By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_by')
->label('Updated By')
->searchable()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListRfqTransporterBids::route('/'),
'create' => Pages\CreateRfqTransporterBid::route('/create'),
'view' => Pages\ViewRfqTransporterBid::route('/{record}'),
'edit' => Pages\EditRfqTransporterBid::route('/{record}/edit'),
];
}
// public static function getEloquentQuery(): Builder
// {
// return parent::getEloquentQuery()
// ->withoutGlobalScopes([
// SoftDeletingScope::class,
// ]);
// }
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Filament\Resources\RfqTransporterBidResource\Pages;
use App\Filament\Resources\RfqTransporterBidResource;
use App\Models\RfqTransporterBid;
use App\Models\User;
use App\Notifications\PushAlertNotification;
use Filament\Actions;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateRfqTransporterBid extends CreateRecord
{
protected static string $resource = RfqTransporterBidResource::class;
protected function afterCreate(): void
{
$record = $this->record;
// Calculate rank based on total_freight_charge
$rank = RfqTransporterBid::where('request_quotation_id', $this->record->request_quotation_id)
->orderBy('total_freight_charge')
->pluck('id')
->search($this->record->id) + 1;
$recipients = User::role(['Super Admin', 'Rfq Supervisor'])->get();
$currentUser = Filament::auth()->user();
if ($currentUser && ! $recipients->contains('id', $currentUser->id)) {
$recipients->push($currentUser);
}
// $user1 = Filament::auth()->user();
$rfqNumber = $this->record->requestQuotation->rfq_number;
$body = "{$currentUser->name} has updated the bid for RFQ No '{$rfqNumber}'. The current rank is #{$rank}.";
Notification::make()
->title('Rank Updated')
->body("{$currentUser->name} has updated the bid for RFQ No '{$rfqNumber}'. The current rank is #{$rank}.")
->success()
->sendToDatabase($recipients);
// Push notification
foreach ($recipients as $user) {
$user->notify(
new PushAlertNotification(
'New Bid Added',
$body
)
);
}
\Log::info('Create bid notification sent', [
'bid_id' => $record->id,
'rank' => $rank,
'recipients' => $recipients->pluck('id'),
]);
}
}

View File

@@ -0,0 +1,175 @@
<?php
namespace App\Filament\Resources\RfqTransporterBidResource\Pages;
use App\Filament\Resources\RfqTransporterBidResource;
use App\Models\RequestQuotation;
use App\Models\RfqTransporterBid;
use App\Models\SpotRateTransportMaster;
use App\Models\User;
use App\Notifications\PushAlertNotification;
use Filament\Actions;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Support\Facades\Log;
class EditRfqTransporterBid extends EditRecord
{
protected static string $resource = RfqTransporterBidResource::class;
protected function afterSave(): void
{
if (! $this->record->wasChanged('total_freight_charge')) {
return;
}
$rank = RfqTransporterBid::where('request_quotation_id', $this->record->request_quotation_id)
->orderBy('total_freight_charge')
->pluck('id')
->search($this->record->id) + 1;
$requestQuotation = RequestQuotation::findOrFail(
$this->record->request_quotation_id
);
$spotRateId = $requestQuotation->spot_rate_transport_master_id;
$spotRate = SpotRateTransportMaster::findOrFail($spotRateId);
$userNames = $spotRate->user_name;
Log::info('User names from spot rate', [
'user_name_raw' => $spotRate->user_name,
]);
if (!is_array($userNames)) {
Log::warning('user_name is not array, resetting', [
'user_name' => $userNames,
]);
$userNames = [];
}
$users = User::whereIn('name', $userNames)->get();
Log::info('Matched users', [
'count' => $users->count(),
'user_ids' => $users->pluck('id'),
]);
// $recipients = User::role(['Super Admin', 'Rfq Supervisor', 'TransporterBid Employee'])->get();
// $recipients1 = User::role(['Super Admin', 'Rfq Supervisor', 'TransporterBid Employee'])->whereHas('pushSubscriptions')->get();
$currentUser = Filament::auth()->user();
// if ($currentUser && ! $recipients1->contains('id', $currentUser->id)) {
// $recipients1->push($currentUser);
// }
// if ($currentUser && ! $recipients->contains('id', $currentUser->id)) {
// $recipients->push($currentUser);
// }
// $user1 = Filament::auth()->user();
$rfqNumber = $this->record->requestQuotation->rfq_number;
$body = "{$currentUser->name} has updated the bid for RFQ No '{$rfqNumber}'. The current rank is #{$rank}.";
// Notification::make()
// ->title('Rank Updated')
// ->body("{$currentUser->name} current rank is #{$rank}")
// ->success()
// ->sendToDatabase($recipients);
// \Log::info('Notification sent', [
// 'rank' => $rank,
// 'recipients' => $recipients->pluck('id'),
// ]);
Notification::make()
->title('Rank Updated')
->body("{$currentUser->name} has updated the bid for RFQ No '{$rfqNumber}'. The current rank is #{$rank}.")
->success()
->sendToDatabase($users);
// foreach ($recipients1 as $user) {
// $user->notify(
// new PushAlertNotification(
// 'Rank Updated',
// $body
// )
// );
// }
// foreach ($users as $user) {
// Log::info('Checking push subscription for user', [
// 'user_id' => $user->id,
// 'name' => $user->name,
// 'subscription_count' => $user->pushSubscriptions()->count(),
// ]);
// if ($user->pushSubscriptions()->exists()) {
// Log::info('Sending push notification', [
// 'user_id' => $user->id,
// ]);
// $user->notify(
// new PushAlertNotification(
// 'Rank Updated',
// $body
// )
// );
// }
// else {
// Log::warning('User has NO push subscription', [
// 'user_id' => $user->id,
// ]);
// }
// }
foreach ($users as $user) {
$count = $user->pushSubscriptions()->count();
Log::info('Checking push subscription for user', [
'user_id' => $user->id,
'name' => $user->name,
'subscription_count' => $count,
]);
if ($count == 0) {
Log::warning('User has NO push subscription', [
'user_id' => $user->id,
]);
continue;
}
Log::info('Sending push notification', [
'user_id' => $user->id,
]);
// ✅ THIS IS ALL YOU NEED
$user->notify(new PushAlertNotification(
'Rank Updated',
$body
));
}
}
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\RfqTransporterBidResource\Pages;
use App\Filament\Resources\RfqTransporterBidResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListRfqTransporterBids extends ListRecords
{
protected static string $resource = RfqTransporterBidResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\RfqTransporterBidResource\Pages;
use App\Filament\Resources\RfqTransporterBidResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewRfqTransporterBid extends ViewRecord
{
protected static string $resource = RfqTransporterBidResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,130 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\SpotRateTransportMasterResource\Pages;
use App\Filament\Resources\SpotRateTransportMasterResource\RelationManagers;
use App\Models\SpotRateTransportMaster;
use App\Models\User;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
class SpotRateTransportMasterResource extends Resource
{
protected static ?string $model = SpotRateTransportMaster::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Request For Quotation';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('group_name')
->label('Group Name')
->required(),
Forms\Components\Select::make('user_name')
->label('User')
->multiple()
->preload()
->reactive()
->options(
User::pluck('name', 'name')->toArray()
)
->searchable()
->required(),
Forms\Components\Hidden::make('id')
->label('id'),
Forms\Components\Hidden::make('created_by')
->label('Created By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->label('Updated By')
->default(Filament::auth()->user()?->name),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('group_name')
->label('Group Name')
->sortable(),
Tables\Columns\TextColumn::make('user_name')
->label('User Name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListSpotRateTransportMasters::route('/'),
'create' => Pages\CreateSpotRateTransportMaster::route('/create'),
'view' => Pages\ViewSpotRateTransportMaster::route('/{record}'),
'edit' => Pages\EditSpotRateTransportMaster::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Filament\Resources\SpotRateTransportMasterResource\Pages;
use App\Filament\Resources\SpotRateTransportMasterResource;
use App\Models\SpotRateTransportMaster;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateSpotRateTransportMaster extends CreateRecord
{
protected static string $resource = SpotRateTransportMasterResource::class;
protected function beforeCreate(): void
{
$groupName = $this->data['group_name'] ?? null;
$userNames = $this->data['user_name'] ?? [];
foreach ($userNames as $userName) {
$query = SpotRateTransportMaster::where('group_name', $groupName)
->whereJsonContains('user_name', $userName);
if ($query->exists()) {
Notification::make()
->title('Duplicate User')
->body("User {$userName} already exists in this group.")
->danger()
->persistent()
->send();
// Prevent create
$this->halt();
return;
}
}
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Filament\Resources\SpotRateTransportMasterResource\Pages;
use App\Filament\Resources\SpotRateTransportMasterResource;
use App\Models\SpotRateTransportMaster;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
class EditSpotRateTransportMaster extends EditRecord
{
protected static string $resource = SpotRateTransportMasterResource::class;
protected function beforeSave(): void
{
$groupName = $this->data['group_name'] ?? null;
$userNames = $this->data['user_name'] ?? [];
$recordId = $this->record->id ?? null;
foreach ($userNames as $userName) {
$query = SpotRateTransportMaster::where('group_name', $groupName)
->whereJsonContains('user_name', $userName);
// Exclude current record for update
if ($recordId) {
$query->where('id', '!=', $recordId);
}
if ($query->exists()) {
Notification::make()
->title('Duplicate User')
->body("User {$userName} already exists in this group.")
->danger()
->persistent()
->send();
// Prevent save/update
$this->halt();
return;
}
}
}
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\SpotRateTransportMasterResource\Pages;
use App\Filament\Resources\SpotRateTransportMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListSpotRateTransportMasters extends ListRecords
{
protected static string $resource = SpotRateTransportMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\SpotRateTransportMasterResource\Pages;
use App\Filament\Resources\SpotRateTransportMasterResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewSpotRateTransportMaster extends ViewRecord
{
protected static string $resource = SpotRateTransportMasterResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -20,6 +20,7 @@ use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Facades\Schema;
use Closure;
class StickerDetailResource extends Resource
{
@@ -35,13 +36,38 @@ class StickerDetailResource extends Resource
->schema([
Forms\Components\Select::make('sticker_structure_detail_id')
->label('Sticker ID')
->reactive()
->relationship('stickerStructureDetail', 'sticker_id')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->required(),
->required()
->afterStateUpdated(function (callable $get, callable $set) {
// if ($get('element_id')) {
// return;
// }
$structureId = $get('sticker_structure_detail_id');
$set('design_element_type', null);
$set('element_id', null);
if (!$structureId) {
$set('element_id', null);
return;
}
$maxId = StickerDetail::where('sticker_structure_detail_id', $structureId)
->max('element_id');
$nextId = $maxId ? ((int) $maxId + 1) : 1;
$formattedId = str_pad($nextId, 3, '0', STR_PAD_LEFT);
$set('element_id', $formattedId);
}),
Forms\Components\Select::make('design_element_type')
->label('Design Element Type')
->reactive()
->options([
'Text' => 'Text',
'Shape' => 'Shape',
@@ -49,7 +75,9 @@ class StickerDetailResource extends Resource
'QR' => 'QR',
]),
Forms\Components\TextInput::make('element_id')
->label('Element ID'),
->label('Element ID')
->readOnly()
->reactive(),
Forms\Components\Select::make('element_type')
->label('Element Type')
->options([
@@ -79,62 +107,142 @@ class StickerDetailResource extends Resource
->toArray()
),
Forms\Components\TextInput::make('string_value')
->label('String Value'),
->label('String Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\TextInput::make('string_font')
->label('String Font'),
->label('String Font')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\TextInput::make('string_size')
->label('String Size'),
Forms\Components\TextInput::make('element_colour')
->label('Element Colour'),
Forms\Components\TextInput::make('string_align')
->label('String Align'),
->label('String Size')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\Select::make('element_colour')
->label('Element Colour')
->options([
'' => 'Default (Black)',
'#000000' => 'Black',
'#FFFFFF' => 'White',
'#FF0000' => 'Red',
'#00FF00' => 'Lime',
'#0000FF' => 'Blue',
'#FFFF00' => 'Yellow',
'#00FFFF' => 'Cyan',
'#FF00FF' => 'Magenta',
'#800000' => 'Maroon',
'#808000' => 'Olive',
'#008000' => 'Green',
'#800080' => 'Purple',
'#008080' => 'Teal',
'#808080' => 'Gray',
'#C0C0C0' => 'Silver',
'#FFA500' => 'Orange',
'#FFC0CB' => 'Pink',
'#A52A2A' => 'Brown',
'#87CEEB' => 'Sky Blue',
])
->nullable()
->reactive(),
Forms\Components\Select::make('string_align')
->label('String Align')
->options([
'Left' => 'Left',
'Right' => 'Right',
'Center' => 'Center',
])
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\TextInput::make('string_x_value')
->label('String X Value'),
->label('String X Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\TextInput::make('string_y_value')
->label('String Y Value'),
->label('String Y Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Text'),
Forms\Components\Select::make('shape_name')
->label('Shape Name')
->reactive()
->options([
'Line' => 'Line',
'Rectangle' => 'Rectangle',
]),
'CurvedRectangle' => 'CurvedRectangle',
])
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
Forms\Components\TextInput::make('shape_pen_size')
->label('Shape Pen Size'),
->label('Shape Pen Size')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
Forms\Components\TextInput::make('curve_radius')
->label('Curve Radius')
->reactive()
->visible(fn ($get) => $get('shape_name') == 'CurvedRectangle'),
Forms\Components\TextInput::make('shape_x1_value')
->label('Shape X1 Value'),
->label('Shape X1 Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
Forms\Components\TextInput::make('shape_y1_value')
->label('Shape Y1 Value'),
->label('Shape Y1 Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
Forms\Components\TextInput::make('shape_x2_value')
->label('Shape X2 Value'),
->label('Shape X2 Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
Forms\Components\TextInput::make('shape_y2_value')
->label('Shape Y2 Value'),
Forms\Components\FileUpload::make('image_path')
->label('Image')
->image()
->directory('sticker-images')
->visibility('public')
->preserveFilenames(false)
->required(false),
Forms\Components\TextInput::make('image_type')
->label('Image Type'),
->label('Shape Y2 Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Shape'),
// Forms\Components\FileUpload::make('image_path')
// ->label('Image')
// ->image()
// ->directory('sticker-images')
// ->visibility('public')
// ->preserveFilenames(false)
// ->required(false)
// ->reactive()
// ->visible(fn ($get) => $get('design_element_type') == 'Image'),
// Forms\Components\TextInput::make('image_type')
// ->label('Image Type')
// ->reactive()
// ->visible(fn ($get) => $get('design_element_type') == 'Image'),
Forms\Components\TextInput::make('image_x')
->label('Image X'),
->label('Image X')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Image'),
Forms\Components\TextInput::make('image_y')
->label('Image Y'),
->label('Image Y')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Image'),
Forms\Components\TextInput::make('image_width')
->label('Image Width'),
->label('Image Width')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Image'),
Forms\Components\TextInput::make('image_height')
->label('Image Height'),
->label('Image Height')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'Image'),
Forms\Components\TextInput::make('qr_value')
->label('QR Value'),
->label('QR Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
Forms\Components\TextInput::make('qr_align')
->label('QR Align'),
->label('QR Align')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
Forms\Components\TextInput::make('qr_size')
->label('QR Size'),
->label('QR Size')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
Forms\Components\TextInput::make('qr_x_value')
->label('QR X Value'),
->label('QR X Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
Forms\Components\TextInput::make('qr_y_value')
->label('QR Y Value'),
->label('QR Y Value')
->reactive()
->visible(fn ($get) => $get('design_element_type') == 'QR'),
Forms\Components\Hidden::make('created_by')
->label('created_by')
->default(Filament::auth()->user()?->name),
@@ -182,9 +290,9 @@ class StickerDetailResource extends Resource
Tables\Columns\TextColumn::make('string_size')
->label('String Size')
->alignCenter(),
Tables\Columns\TextColumn::make('element_colour')
->label('Element Colour')
->alignCenter(),
// Tables\Columns\TextColumn::make('element_colour')
// ->label('Element Colour')
// ->alignCenter(),
Tables\Columns\TextColumn::make('string_align')
->label('String Align')
->alignCenter(),
@@ -200,6 +308,8 @@ class StickerDetailResource extends Resource
Tables\Columns\TextColumn::make('shape_pen_size')
->label('Shape Pen Size')
->alignCenter(),
Tables\Columns\TextColumn::make('curve_radius')
->label('Curve Radius'),
Tables\Columns\TextColumn::make('shape_x1_value')
->label('Shape X1 Value')
->alignCenter(),
@@ -212,12 +322,6 @@ class StickerDetailResource extends Resource
Tables\Columns\TextColumn::make('shape_y2_value')
->label('Shape Y2 Value')
->alignCenter(),
Tables\Columns\TextColumn::make('image_path')
->label('Image Path')
->alignCenter(),
Tables\Columns\TextColumn::make('image_type')
->label('Image Type')
->alignCenter(),
Tables\Columns\TextColumn::make('image_x')
->label('Image X')
->alignCenter(),

View File

@@ -6,18 +6,24 @@ use App\Filament\Exports\StickerMappingMasterExporter;
use App\Filament\Imports\StickerMappingMasterImporter;
use App\Filament\Resources\StickerMappingMasterResource\Pages;
use App\Filament\Resources\StickerMappingMasterResource\RelationManagers;
use App\Models\Plant;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\Machine;
use App\Models\StickerMappingMaster;
use App\Models\StickerStructureDetail;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
class StickerMappingMasterResource extends Resource
{
@@ -25,143 +31,424 @@ class StickerMappingMasterResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
protected static ?string $navigationGroup = 'Customized Sticker Printing';
// public static function form(Form $form): Form
// {
// return $form
// ->schema([
// Forms\Components\TextInput::make('plant_id')
// ->required()
// ->numeric(),
// Forms\Components\TextInput::make('item_id')
// ->required()
// ->numeric(),
// Forms\Components\Textarea::make('sticker1')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('sticker2')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('sticker3')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('sticker4')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('sticker5')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('created_by')
// ->columnSpanFull(),
// Forms\Components\Textarea::make('updated_by')
// ->columnSpanFull(),
// ]);
// }
protected static ?int $navigationSort = 16;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->reactive()
->relationship('plant', 'name')
->options(function (callable $get) {
$userHas = Filament::auth()->user()->plant_id;
return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
})
->required(),
Forms\Components\Select::make('item_id')
->label('Item')
->reactive()
->options(function (callable $get) {
{
return $form
->schema([
/* -------- Basic Mapping -------- */
Section::make('Basic Mapping')
->schema([
Select::make('plant_id')
->label('Plant')
->reactive()
->relationship('plant', 'name')
->required(),
Select::make('item_characteristic_id')
->label('Item Code')
->reactive()
//->relationship('item', 'code')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
if (! $plantId) {
return [];
}
return \App\Models\Item::where('plant_id', $plantId)->pluck('code', 'id');
})
->required(),
Forms\Components\TextInput::make('sticker1')
->label('Sticker Label 1')
->required(),
Forms\Components\TextInput::make('sticker2')
->label('Sticker Label 2'),
Forms\Components\TextInput::make('sticker3')
->label('Sticker Label 3'),
Forms\Components\TextInput::make('sticker4')
->label('Sticker Label 4'),
Forms\Components\TextInput::make('sticker5')
->label('Sticker Label 5'),
Forms\Components\Hidden::make('created_by')
->label('Created By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->label('Updated By')
->default(Filament::auth()->user()?->name),
]);
}
return ItemCharacteristic::query()
->whereHas('item', function ($query) use ($plantId) {
$query->where('plant_id', $plantId);
})
->with('item')
->get()
->mapWithKeys(fn ($ic) => [
$ic->id => $ic->item->code,
]);
})
->searchable()
->required(),
])
->columns(2),
/* -------- Sticker 1 -------- */
Section::make('Sticker 1')
->schema([
Select::make('sticker_structure1_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker1_machine_id')
->label('Work Center')
//->relationship('sticker1Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker1_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 2 -------- */
Section::make('Sticker 2')
->schema([
Select::make('sticker_structure2_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker2_machine_id')
->label('Work Center')
// ->relationship('sticker2Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker2_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 3 -------- */
Section::make('Sticker 3')
->schema([
Select::make('sticker_structure3_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker3_machine_id')
->label('Work Center')
//->relationship('sticker3Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker3_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 4 -------- */
Section::make('Sticker 4')
->schema([
Select::make('sticker_structure4_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker4_machine_id')
->label('Work Center')
//->relationship('sticker4Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker4_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 5 -------- */
Section::make('Sticker 5')
->schema([
Select::make('sticker_structure5_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker5_machine_id')
->label('Work Center')
//->relationship('sticker5Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker5_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 6 -------- */
Section::make('Sticker 6')
->schema([
Select::make('sticker_structure6_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker6_machine_id')
->label('Work Center')
//->relationship('sticker6Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker6_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 7 -------- */
Section::make('Sticker 7')
->schema([
Select::make('sticker_structure7_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker7_machine_id')
->label('Work Center')
//->relationship('sticker7Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker7_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
/* -------- Sticker 8 -------- */
Section::make('Sticker 8')
->schema([
Select::make('sticker_structure8_id')
->label('Sticker ID')
->options(function (callable $get) {
return StickerStructureDetail::pluck('sticker_id', 'id');
})
->searchable(),
Select::make('sticker8_machine_id')
->label('Work Center')
//->relationship('sticker8Machine', 'name')
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
TextInput::make('sticker8_print_ip')
->label('Printer IP')
->ipv4(),
])
->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('item.code')
->label('Item Code')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker1')
->label('Sticker Label 1')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker2')
->label('Sticker Label 2')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker3')
->label('Sticker Label 3')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker4')
->label('Sticker Label 4')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker5')
->label('Sticker Label 5')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->label('Import Sticker Mapping Masters')
->color('warning')
->importer(StickerMappingMasterImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import sticker mapping master');
}),
ExportAction::make()
->label('Export Sticker Mapping Masters')
->color('warning')
->exporter(StickerMappingMasterExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export sticker mapping master');
}),
]);
Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('itemCharacteristic.item.code')
->label('Item')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('sticker1Structure.sticker_id')
->label('Sticker 1')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker1Machine.work_center')
->label('WC 1')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker1_print_ip')
->label('Printer IP 1')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker2Structure.sticker_id')
->label('Sticker 2')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker2Machine.work_center')
->label('WC 2')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker2_print_ip')
->label('Printer IP 2')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker3Structure.sticker_id')
->label('Sticker 3')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker3Machine.work_center')
->label('WC 3')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker3_print_ip')
->label('Printer IP 3')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker4Structure.sticker_id')
->label('Sticker 4')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker4Machine.work_center')
->label('WC 4')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker4_print_ip')
->label('Printer IP 4')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker5Structure.sticker_id')
->label('Sticker 5')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker5Machine.work_center')
->label('WC 5')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker5_print_ip')
->label('Printer IP 5')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker6Structure.sticker_id')
->label('Sticker 6')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker6Machine.work_center')
->label('WC 6')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker6_print_ip')
->label('Printer IP 6')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker7Structure.sticker_id')
->label('Sticker 7')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker7Machine.work_center')
->label('WC 7')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker7_print_ip')
->label('Printer IP 7')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker8Structure.sticker_id')
->label('Sticker 8')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker8Machine.work_center')
->label('WC 8')
->alignCenter(),
Tables\Columns\TextColumn::make('sticker8_print_ip')
->label('Printer IP 8')
->alignCenter(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->alignCenter()
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->importer(StickerMappingMasterImporter::class)
->label('Import Sticker Mapping Master')
->color('warning')
->visible(function () {
return Filament::auth()->user()->can('view import sticker mapping master');
}),
ExportAction::make()
->exporter(StickerMappingMasterExporter::class)
->label('Export Sticker Mapping Master')
->color('warning')
->visible(function () {
return Filament::auth()->user()->can('view export sticker mapping master');
}),
]);
}
public static function getRelations(): array

View File

@@ -0,0 +1,165 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\StickerValidationResource\Pages;
use App\Filament\Resources\StickerValidationResource\RelationManagers;
use App\Models\Machine;
use App\Models\StickerValidation;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\Section;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class StickerValidationResource extends Resource
{
protected static ?string $model = StickerValidation::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Customized Sticker Printing';
public static function form(Form $form): Form
{
return $form
->schema([
Section::make('')
->schema([
Forms\Components\Select::make('plant_id')
->label('Plant')
->reactive()
->relationship('plant', 'name')
->required(),
Forms\Components\Select::make('machine_id')
->label('Work Center')
->required()
->reactive()
->options(function (callable $get) {
$plantId = $get('plant_id');
if (empty($plantId)) {
return [];
}
return Machine::where('plant_id', $plantId)->pluck('work_center', 'id');
})
->searchable(),
Forms\Components\TextInput::make('production_order')
->label('Production Order')
->reactive()
->extraAttributes([
'id' => 'production_order_input',
'x-data' => '{ value: "" }',
'x-model' => 'value',
'wire:keydown.enter.prevent' => 'processProOrder(value)',
]),
Forms\Components\TextInput::make('serial_number')
->label('Serial Number')
->reactive()
->extraAttributes([
'id' => 'serial_number_input',
'x-data' => '{ value: "" }',
'x-model' => 'value',
'wire:keydown.enter.prevent' => 'processSno(value)',
]),
Forms\Components\Hidden::make('created_by')
->label('Created By')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->label('Updated By')
->default(Filament::auth()->user()?->name),
])
->columns(4),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.code')
->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('machine.work_center')
->label('Work Center')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('production_order')
->label('Production Order')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('serial_number')
->label('Serial Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('status')
->label('Status')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListStickerValidations::route('/'),
'create' => Pages\CreateStickerValidation::route('/create'),
'view' => Pages\ViewStickerValidation::route('/{record}'),
'edit' => Pages\EditStickerValidation::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,416 @@
<?php
namespace App\Filament\Resources\StickerValidationResource\Pages;
use App\Filament\Resources\StickerValidationResource;
use App\Models\Item;
use App\Models\ItemCharacteristic;
use App\Models\ProductionQuantity;
use App\Models\StickerDetail;
use App\Models\StickerMappingMaster;
use App\Models\StickerStructureDetail;
use App\Models\StickerValidation;
use App\Services\StickerPdfService;
use Filament\Actions;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateStickerValidation extends CreateRecord
{
protected static string $resource = StickerValidationResource::class;
protected static string $view = 'filament.resources.sticker-validation-resource.create-sticker-validation';
public $ref_number;
public $plantId;
public $workCenter;
public $serNo;
public function getFormActions(): array
{
return [
$this->getCancelFormAction(),
];
}
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('create');
}
public function processProOrder($value)
{
$plantId = $this->form->getState()['plant_id'];
$this->plantId = $plantId;
$this->ref_number = $value;
$this->dispatch('refreshEmptySticker', $plantId, $value);
$this->dispatch('focus-serial-number');
}
public function processSno($serNo)
{
$plantId = $this->form->getState()['plant_id'];
$this->plantId = $plantId;
$workCenter = $this->form->getState()['machine_id'];
$this->workCenter = $workCenter;
$this->ref_number = $this->form->getState()['production_order'];
$this->serNo = $serNo;
$user = Filament::auth()->user();
$operatorName = $user->name;
if (! preg_match('/^([a-zA-Z0-9]{6,})\|([1-9][a-zA-Z0-9]{8,})\|?$/', $this->serNo, $matches)) {
Notification::make()
->danger()
->title('Invalid Serial QR Format')
->body('Scan valid Serial QR code proceed!<br>Sample formats are:<br>123456|1234567890123| OR 123456|1234567890123')
->seconds(3)
->send();
$this->dispatch('playWarnSound');
$this->form->fill([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number,
'serial_number' => null,
]);
$this->dispatch('focus-serial-number');
return;
}
else {
$itemCode = $matches[1];
$serialNumber = $matches[2];
$recFound = ProductionQuantity::where('plant_id', $this->plantId)
->where('production_order', $this->ref_number)
->where('serial_number', $serialNumber)
->first();
if(!$recFound){
Notification::make()
->danger()
->title('Unknown Serial Number')
->body("Scanned serial number '$serialNumber' not found for the given plant and production order")
->seconds(3)
->send();
$this->form->fill([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number,
'serial_number' => null,
]);
return;
}
$duplicate = StickerValidation::where('plant_id', $this->plantId)
->where('production_order', $this->ref_number)
->where('serial_number', $serialNumber)
->first();
if ($duplicate) {
Notification::make()
->danger()
->title('Duplicate Serial Number')
->body("Serial number $serialNumber already exists for this plant and production order!")
->seconds(3)
->send();
$this->form->fill([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number,
'serial_number' => null,
]);
return;
}
$itemC = Item::where('code', $itemCode)
->where('plant_id',$this->plantId)
->first();
$itemId = $itemC->id;
$item = ItemCharacteristic::where('item_id', $itemId)
->where('plant_id',$this->plantId)
->first();
$itemI = $item->id;
$mapping = StickerMappingMaster::where('plant_id', $this->plantId)
->where('item_characteristic_id', $itemI)
->first();
if (!$mapping) {
Notification::make()
->danger()
->title('Sticker Mapping Not Found')
->body("No sticker mapping found for this item and plant.")
->send();
return;
}
$stickers = [];
for ($i = 1; $i <= 8; $i++) {
$machineColumn = "sticker{$i}_machine_id";
$ipColumn = "sticker{$i}_print_ip";
$stickerColumn = "sticker_structure{$i}_id";
$itemColumn = "item_characteristic_id";
if (
!empty($mapping->$machineColumn) &&
!empty($mapping->$stickerColumn)
) {
$stickers[] = [
'machine_id' => $mapping->$machineColumn,
'sticker_id' => $mapping->$stickerColumn,
'item_characteristic' => $mapping->$itemColumn,
'print_ip' => $mapping->$ipColumn,
];
}
}
if (empty($stickers)) {
Notification::make()
->danger()
->title('No Sticker Configuration Found')
->body('No sticker and machine mappings configured for this item and plant.')
->send();
return;
}
StickerValidation::create([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number ?? null,
'serial_number' => $serialNumber,
'status' => 'Printed',
// 'sticker_id' => $matchedSticker,
'created_by' => $operatorName,
'created_at' => now(),
'updated_at' => now(),
]);
Notification::make()
->success()
->title('Sticker Recorded')
->body("Item: $itemCode, Serial: $serialNumber recorded successfully!")
->seconds(3)
->send();
$this->form->fill([
'plant_id' => $this->plantId,
'machine_id' => $this->workCenter,
'production_order' => $this->ref_number,
'serial_number' => null,
]);
$this->dispatch('refreshEmptySticker', $plantId, $this->ref_number);
// foreach ($stickers as $sticker) {
// // $printerName = $this->getCupsPrinterNameByIp($sticker['print_ip']);
// \Log::info("Looking up printer for IP: " . $sticker['print_ip']);
// $printerName = $this->getCupsPrinterNameByIp($sticker['print_ip']);
// \Log::info("Found printer: " . ($printerName ?? 'NULL'));
// if (! $printerName) {
// Notification::make()
// ->danger()
// ->title('Printer Not Found')
// ->body("No CUPS printer configured for IP: {$sticker['print_ip']}")
// ->send();
// return;
// }
// $structure = StickerStructureDetail::findOrFail($sticker['sticker_id']);
// $itemCharacteristic = ItemCharacteristic::where('plant_id', $this->plantId)
// ->where('id', $sticker['item_characteristic'])
// ->firstOrFail();
// $dynamicElements = StickerDetail::where(
// 'sticker_structure_detail_id',
// $structure->id
// )->where('element_type', 'Dynamic')->get();
// /** STEP 3: Stream PDF to CUPS (STDIN) */
// $process = proc_open(
// 'lp -d ' . escapeshellarg($printerName) . ' -o fit-to-page -',
// [
// ['pipe', 'r'], // STDIN
// ['pipe', 'w'], // STDOUT
// ['pipe', 'w'], // STDERR
// ],
// $pipes
// );
// if (! is_resource($process)) {
// Notification::make()
// ->danger()
// ->title('Print Failed')
// ->body('Unable to start CUPS print process.')
// ->send();
// return;
// // continue;
// }
// $pdfContent = (new StickerPdfService())->generatePdf1(
// $structure->sticker_id,
// $dynamicElements,
// $itemCharacteristic,
// $serialNumber,
// $serNo
// );
// fwrite($pipes[0], $pdfContent);
// fclose($pipes[0]);
// $stderr = stream_get_contents($pipes[2]);
// fclose($pipes[1]);
// fclose($pipes[2]);
// $status = proc_close($process);
// if ($status != 0) {
// Notification::make()
// ->danger()
// ->title('Print Failed')
// ->body("CUPS error: {$stderr}")
// ->send();
// return;
// }
// }
foreach ($stickers as $sticker)
{
\Log::info("Looking up printer for IP: " . $sticker['print_ip']);
$printerName = $this->getCupsPrinterNameByIp($sticker['print_ip']);
\Log::info("Found printer: " . ($printerName ?? 'NULL'));
if (! $printerName) {
Notification::make()
->danger()
->title('Printer Not Found')
->body("No CUPS printer configured for IP: {$sticker['print_ip']}")
->send();
return;
}
$structure = StickerStructureDetail::findOrFail($sticker['sticker_id']);
$itemCharacteristic = ItemCharacteristic::where('plant_id', $this->plantId)
->where('id', $sticker['item_characteristic'])
->firstOrFail();
$dynamicElements = StickerDetail::where(
'sticker_structure_detail_id',
$structure->id
)->where('element_type', 'Dynamic')->get();
$pdfContent = (new StickerPdfService())->generatePdf1(
$structure->sticker_id,
$dynamicElements,
$itemCharacteristic,
$serialNumber,
$serNo
);
$tempPdfPath = storage_path('app/temp_sticker_' . uniqid() . '.pdf');
file_put_contents($tempPdfPath, $pdfContent);
exec(
"lp -d " . escapeshellarg($printerName) . " " . escapeshellarg($tempPdfPath),
$output,
$status
);
\Log::info("LP Output:", $output);
\Log::info("LP Status: " . $status);
if ($status != 0) {
Notification::make()
->danger()
->title('Print Failed')
->body("CUPS error while printing.")
->send();
if (file_exists($tempPdfPath)) {
unlink($tempPdfPath);
}
return;
}
if (file_exists($tempPdfPath)) {
unlink($tempPdfPath);
}
}
Notification::make()
->success()
->title('Sticker Printed')
->body("Sticker for Serial Number: $serialNumber printed successfully!")
->seconds(3)
->send();
// [$itemCode, $serialNumber] = explode('|', $serNo);
// $this->dispatch('open-sticker-pdf', [
// 'url' => url("/sticker/pdf/{$itemCode}/{$serialNumber}/$this->plantId/$this->ref_number")
// ]);
}
}
protected function getCupsPrinterNameByIp(string $ip): ?string
{
// exec('lpstat -v 2>&1', $output, $status);
exec('lpstat -h cups:631 -v 2>&1', $output, $status);
if ($status != 0 || empty($output)) {
return null;
}
foreach ($output as $line){
$parts = explode(':', $line, 2);
if (count($parts) < 2) continue;
$printerName = trim(str_replace('device for', '', $parts[0]));
$deviceUri = trim($parts[1]);
if (str_contains($deviceUri, $ip)) {
return $printerName;
}
}
return null;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\StickerValidationResource\Pages;
use App\Filament\Resources\StickerValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditStickerValidation extends EditRecord
{
protected static string $resource = StickerValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\StickerValidationResource\Pages;
use App\Filament\Resources\StickerValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListStickerValidations extends ListRecords
{
protected static string $resource = StickerValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\StickerValidationResource\Pages;
use App\Filament\Resources\StickerValidationResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewStickerValidation extends ViewRecord
{
protected static string $resource = StickerValidationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,276 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\VisitorEntryResource\Pages;
use App\Filament\Resources\VisitorEntryResource\RelationManagers;
use App\Models\VisitorEntry;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class VisitorEntryResource extends Resource
{
protected static ?string $model = VisitorEntry::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('mobile_number')
->label('Mobile Number')
->length(10)
->reactive()
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^0-9]/g, "").slice(0, 10)', // blocks non-numbers + limits to 10 chars
'maxlength' => 10,
])
->required()
->extraAttributes([
'id' => 'mobile_number_input',
'x-data' => '{ value: "" }',
'x-model' => 'value',
'wire:keydown.enter.prevent' => 'processMobile(value)',
]),
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->reactive()
->extraInputAttributes([
'oninput' => 'this.value = this.value.replace(/[^a-zA-Z\s]/g, "")',
]),
Forms\Components\Select::make('type')
->label('Type')
->reactive()
->options([
'Student' => 'Student',
'Consultant' => 'Consultant',
'Vendor' => 'Vendor',
'Other' => 'Other',
])
->required()
->dehydrateStateUsing(function ($state, callable $get) {
return $state == 'Other'
? $get('other_type')
: $state;
}),
Forms\Components\TextInput::make('other_type')
->label('Specify Type')
->reactive()
->visible(fn (callable $get) => $get('type') == 'Other')
->required(fn (callable $get) => $get('type') == 'Other')
->dehydrated(false),
Forms\Components\TextInput::make('company')
->label('Company')
->required(),
Forms\Components\Select::make('department')
->label('Employee Department')
->options(
\App\Models\EmployeeMaster::distinct()
->pluck('department', 'department')
)
->required()
->reactive()
->afterStateUpdated(function (callable $set) {
$set('employee_master_id', null);
$set('code', null);
}),
// Forms\Components\Select::make('employee_master_id')
// ->label('Recipient Employee')
// ->required()
// ->options(function (callable $get) {
// $department = $get('department');
// if (!$department) {
// return [];
// }
// return \App\Models\EmployeeMaster::where('department', $department)
// ->pluck('name', 'id');
// })
// ->reactive()
// ->afterStateUpdated(function (callable $set, callable $get, ?string $state) {
// $department = $get('department');
// $employee = \App\Models\EmployeeMaster::where('id', $state)
// ->where('department', $department)
// ->first();
// $set('code', $employee ? $employee->code : '');
// }),
Forms\Components\Select::make('employee_master_id')
->label('Recipient Employee')
->required()
->options(function (callable $get) {
$department = $get('department');
// Always load ALL employees, filter by department if set
if ($department) {
return \App\Models\EmployeeMaster::where('department', $department)
->pluck('name', 'id');
}
// Fallback: load all so fill() can always match the ID
return \App\Models\EmployeeMaster::pluck('name', 'id');
})
->reactive()
->afterStateUpdated(function (callable $set, ?string $state) {
$employee = \App\Models\EmployeeMaster::find($state);
$set('code', $employee?->code ?? '');
}),
Forms\Components\TextInput::make('code')
->label('Employee Code')
->readOnly(),
Forms\Components\Textarea::make('purpose_of_visit')
->label('Purpose of Visit')
->required(),
Forms\Components\TextInput::make('number_of_person')
->numeric()
->default(1)
->required(),
Forms\Components\DateTimePicker::make('in_time')
->label('In Time'),
Forms\Components\DateTimePicker::make('out_time')
->label('Out Time'),
Forms\Components\View::make('components.webcam-field')
->columnSpanFull(),
Forms\Components\Hidden::make('photo'),
Forms\Components\Hidden::make('created_by')
->label('created_by')
->default(Filament::auth()->user()?->name),
Forms\Components\Hidden::make('updated_by')
->label('updated_by')
->default(Filament::auth()->user()?->name),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('No.')
->label('NO')
->alignCenter()
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\ImageColumn::make('photo')
->label('Photo')
->disk('public')
->height(50)
->width(50)
// ->defaultImageUrl('https://ui-avatars.com/api/?name=Visitor&background=555&color=fff')
->defaultImageUrl(asset('images/profile.png'))
->alignCenter()
->extraImgAttributes(['style' => 'border-radius: 6px; object-fit: cover;']),
Tables\Columns\TextColumn::make('type')
->label('Visitor Type')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('name')
->label('Visitor Name')
->sortable()
->alignCenter()
->searchable(),
Tables\Columns\TextColumn::make('mobile_number')
->label('Visitor Mobile Number')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('employeeMaster.name')
->label('Recipient Name')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('employeeMaster.code')
->label('Receipient ID')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('employeeMaster.department')
->label('Receipient Department')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('number_of_person')
->label('Number of Person')
->numeric()
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('in_time')
->label('In Time')
->dateTime()
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('out_time')
->label('Out Time')
->dateTime()
->sortable()
->alignCenter(),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->alignCenter(),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListVisitorEntries::route('/'),
'create' => Pages\CreateVisitorEntry::route('/create'),
'view' => Pages\ViewVisitorEntry::route('/{record}'),
'edit' => Pages\EditVisitorEntry::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,150 @@
<?php
namespace App\Filament\Resources\VisitorEntryResource\Pages;
use App\Filament\Resources\VisitorEntryResource;
use App\Models\EmployeeMaster;
use App\Models\VisitorEntry;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
use Livewire\Attributes\On;
use Storage;
class CreateVisitorEntry extends CreateRecord
{
protected static string $resource = VisitorEntryResource::class;
public $capturedPhoto;
// #[On('photo-captured')]
// public function handlePhotoCapture(string $photo): void
// {
// // Puts the Base64 photo into the form's data array
// $this->data['photo'] = $photo;
// }
public function processMobile($mobile)
{
$visitor = VisitorEntry::where('mobile_number', $mobile)->latest()->first();
if ($visitor) {
$employee = EmployeeMaster::where('id', $visitor->employee_master_id)->first();
$this->form->fill([
'mobile_number' => $mobile ?? '',
'name' => $visitor->name ?? '',
'company' => $visitor->company ?? '',
'type' => $visitor->type ?? '',
'department' => $employee->department ?? '',
'employee_master_id' => $visitor->employee_master_id->name ?? '',
'code' => $employee->code ?? '',
]);
}
else {
$this->form->fill([
'mobile_number' => $mobile ?? '',
'name' => $visitor->name ?? '',
'company' => $visitor->company ?? '',
'type' => $visitor->type ?? '',
'department' => $employee->department ?? '',
'employee_master_id' => $visitor->employee_master_id->name ?? '',
'code' => $employee->code ?? '',
]);
}
}
// protected function mutateFormDataBeforeCreate(array $data): array
// {
// if (
// !empty($data['photo']) &&
// str_starts_with($data['photo'], 'data:image')
// ) {
// // Step A: Strip the "data:image/jpeg;base64," prefix
// $imageData = explode(',', $data['photo'])[1];
// // Step B: Generate a unique filename
// $filename = 'visitor_' . time() . '_' . uniqid() . '.jpg';
// // Step C: Decode Base64 and save as a real .jpg file
// $path = 'visitor-photos/' . $filename;
// Storage::disk('public')->put($path, base64_decode($imageData));
// // Step D: Replace the Base64 string with just the file path
// $data['photo'] = $path;
// }
// return $data;
// }
#[On('photo-captured')]
public function handlePhotoCapture(string $photo): void
{
$this->data['photo'] = $photo;
\Log::info('WEBCAM: photo-captured event received, length: ' . strlen($photo));
}
// protected function mutateFormDataBeforeCreate(array $data): array
// {
// \Log::info('WEBCAM: mutateFormDataBeforeCreate called, photo value: ' . substr($data['photo'] ?? 'NULL', 0, 50));
// if (
// !empty($data['photo']) &&
// str_starts_with($data['photo'], 'data:image')
// ) {
// $imageData = explode(',', $data['photo'])[1];
// $filename = 'visitor_' . time() . '_' . uniqid() . '.jpg';
// $path = 'visitor-photos/' . $filename;
// Storage::disk('public')->put($path, base64_decode($imageData));
// $data['photo'] = $path;
// \Log::info('WEBCAM: photo saved to ' . $path);
// }
// return $data;
// }
protected function mutateFormDataBeforeCreate(array $data): array
{
if (
!empty($data['photo']) &&
str_starts_with($data['photo'], 'data:image')
) {
try {
$imageData = explode(',', $data['photo'])[1];
$filename = 'visitor_' . time() . '_' . uniqid() . '.jpg';
$path = 'visitor-photos/' . $filename;
$decoded = base64_decode($imageData);
$saved = Storage::disk('public')->put($path, $decoded);
\Log::info('PHOTO UPLOAD (PUBLIC):', [
'filename' => $filename,
'path' => $path,
'size_bytes' => strlen($decoded),
'saved' => $saved ? 'SUCCESS' : 'FAILED',
]);
$data['photo'] = $path;
} catch (\Exception $e) {
\Log::error('PHOTO UPLOAD ERROR: ' . $e->getMessage());
}
}
return $data;
}
public function setPhoto(string $photo): void
{
$this->capturedPhoto = $photo;
// Change this ↓ to dispatch to parent explicitly
$this->dispatch('photo-captured', photo: $photo)->to(\App\Filament\Resources\VisitorEntryResource\Pages\CreateVisitorEntry::class);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace App\Filament\Resources\VisitorEntryResource\Pages;
use App\Filament\Resources\VisitorEntryResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
use Livewire\Attributes\On;
use Storage;
class EditVisitorEntry extends EditRecord
{
protected static string $resource = VisitorEntryResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
#[On('photo-captured')]
public function handlePhotoCapture(string $photo): void
{
$this->data['photo'] = $photo;
}
protected function mutateFormDataBeforeSave(array $data): array
{
if (
!empty($data['photo']) &&
str_starts_with($data['photo'], 'data:image')
) {
// Delete the old photo file if one exists
$oldPhoto = $this->record->photo;
if ($oldPhoto && Storage::disk('public')->exists($oldPhoto)) {
Storage::disk('public')->delete($oldPhoto);
}
// Save the new photo
$imageData = explode(',', $data['photo'])[1];
$filename = 'visitor_' . time() . '_' . uniqid() . '.jpg';
$path = 'visitor-photos/' . $filename;
Storage::disk('public')->put($path, base64_decode($imageData));
$data['photo'] = $path;
}
return $data;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\VisitorEntryResource\Pages;
use App\Filament\Resources\VisitorEntryResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListVisitorEntries extends ListRecords
{
protected static string $resource = VisitorEntryResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\VisitorEntryResource\Pages;
use App\Filament\Resources\VisitorEntryResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewVisitorEntry extends ViewRecord
{
protected static string $resource = VisitorEntryResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,146 @@
<?php
namespace App\Filament\Widgets;
use App\Models\RequestQuotation;
use App\Models\RfqTransporterBid;
use Filament\Facades\Filament;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;
class RfqChart extends BaseWidget
{
// protected function getStats(): array
// {
// $transporter = session('transport_name');
// $rfqNumber = session('rfq_number');
// if (!$transporter || !$rfqNumber) {
// return [
// Stat::make('Total Freight Charge', '-'),
// Stat::make('Rank', '-'),
// ];
// }
// $selectedRfq = RequestQuotation::query()
// ->where('transporter_name', $transporter)
// ->where('rfq_number', $rfqNumber)
// ->first();
// if (!$selectedRfq) {
// return [
// Stat::make('Total Freight Charge', '-'),
// Stat::make('Rank', '-'),
// ];
// }
// $myAmount = (float) $selectedRfq->total_freight_charge;
// $rank = RequestQuotation::query()
// ->whereRaw(
// 'CAST(total_freight_charge AS DECIMAL(10,2)) < ?',
// [$myAmount]
// )
// ->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))')
// ->distinct()
// ->count() + 1;
// $medal = match (true) {
// $rank == 1 => '🥇',
// $rank == 2 => '🥈',
// $rank == 3 => '🥉',
// default => '',
// };
// return [
// Stat::make(
// 'Total Freight Charge',
// number_format($selectedRfq->total_freight_charge, 2)
// )
// ->description('Transporter: ' . $selectedRfq->transporter_name)
// ->color($rank == 1 ? 'success' : 'primary'),
// Stat::make(
// 'Rank',
// trim("{$medal} #{$rank}")
// )
// ->description('Among all transporters')
// ->color(
// $rank == 1 ? 'success' :
// ($rank <= 3 ? 'warning' : 'gray')
// ),
// ];
// }
protected function getStats(): array
{
$transporter = session('transport_name');
$rfqNumber = session('rfq_id');
if (!$transporter || !$rfqNumber) {
return [
Stat::make('Total Freight Charge', '-'),
Stat::make('Rank', '-'),
];
}
$selectedRfq = RfqTransporterBid::query()
->where('transporter_name', $transporter)
->where('request_quotation_id', $rfqNumber)
->first();
if (!$selectedRfq) {
return [
Stat::make('Total Freight Charge', '-'),
Stat::make('Rank', '-'),
];
}
$myAmount = (float) $selectedRfq->total_freight_charge;
// $rank = RfqTransporterBid::query()
// ->whereRaw(
// 'CAST(total_freight_charge AS DECIMAL(10,2)) < ?',
// [$myAmount]
// )
// ->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))')
// ->distinct()
// ->count() + 1;
$rank = RfqTransporterBid::query()
->where('request_quotation_id', $rfqNumber) // 🔥 MISSING CONDITION
->whereRaw(
'CAST(total_freight_charge AS DECIMAL(10,2)) < ?',
[$myAmount]
)
->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))')
->distinct()
->count() + 1;
$medal = match (true) {
$rank == 1 => '🥇',
$rank == 2 => '🥈',
$rank == 3 => '🥉',
default => '',
};
return [
Stat::make(
'Total Freight Charge',
number_format($selectedRfq->total_freight_charge, 2)
)
->description('Transporter: ' . $selectedRfq->transporter_name)
->color($rank == 1 ? 'success' : 'primary'),
Stat::make(
'Rank',
trim("{$medal} #{$rank}")
)
->description('Among all transporters')
->color(
$rank == 1 ? 'success' :
($rank <= 3 ? 'warning' : 'gray')
),
];
}
}

View File

@@ -0,0 +1,205 @@
<?php
namespace App\Filament\Widgets;
use App\Models\RfqTransporterBid;
use Filament\Widgets\ChartWidget;
use Illuminate\Support\Js;
class RfqRankChart extends ChartWidget
{
protected static ?string $heading = 'Chart';
// protected function getData(): array
// {
// $rfqId = session('rfq_id');
// if (!$rfqId) {
// return [
// 'datasets' => [],
// 'labels' => [],
// ];
// }
// // Get bids ordered by lowest freight charge
// $bids = RfqTransporterBid::query()
// ->where('request_quotation_id', $rfqId)
// ->orderByRaw('CAST(total_freight_charge AS DECIMAL(10,2)) ASC')
// ->get();
// // $labels = [];
// // $ranks = [];
// // $rank = 1;
// // foreach ($bids as $bid) {
// // $labels[] = $bid->transporter_name;
// // $ranks[] = $rank++;
// // }
// // return [
// // 'datasets' => [
// // [
// // 'label' => 'Rank (Lower is Better)',
// // 'data' => $ranks,
// // 'fill' => false,
// // 'tension' => 0.3,
// // ],
// // ],
// // 'labels' => $labels,
// // ];
// $labels = [];
// $ranks = [];
// $colors = [];
// $rank = 1;
// foreach ($bids as $bid) {
// $labels[] = $bid->transporter_name;
// $ranks[] = $rank;
// // Rank-based colors
// $colors[] = match ($rank) {
// 1 => '#FFD700', // Gold
// 2 => '#C0C0C0', // Silver
// 3 => '#CD7F32', // Bronze
// default => '#3B82F6', // Blue
// };
// $rank++;
// }
// return [
// 'datasets' => [
// [
// 'label' => 'Rank (1 = Best)',
// 'data' => $ranks,
// // 🎨 Styling
// 'borderColor' => '#3B82F6',
// 'backgroundColor' => $colors,
// 'pointBackgroundColor' => $colors,
// 'pointBorderColor' => '#000',
// 'pointRadius' => 7,
// 'pointHoverRadius' => 10,
// 'borderWidth' => 3,
// 'tension' => 0.4,
// 'fill' => false,
// ],
// ],
// 'labels' => $labels,
// ];
// }
protected function getData(): array
{
$rfqId = session('rfq_id');
if (!$rfqId) {
return [
'datasets' => [],
'labels' => [],
];
}
/**
* STEP 1: Get bids sorted by freight charge (for ranking)
*/
$rankedBids = RfqTransporterBid::query()
->where('request_quotation_id', $rfqId)
->orderByRaw('CAST(total_freight_charge AS DECIMAL(10,2)) ASC')
->get();
$rankMap = [];
$rank = 1;
foreach ($rankedBids as $bid) {
$rankMap[$bid->id] = $rank++;
}
/**
* STEP 2: Get bids in natural order (for wave effect)
* You can change orderBy to:
* - created_at
* - transporter_name
*/
$chartBids = RfqTransporterBid::query()
->where('request_quotation_id', $rfqId)
->orderBy('id')
->get();
$labels = [];
$amounts = [];
$colors = [];
$ranks = [];
foreach ($chartBids as $bid) {
$labels[] = $bid->transporter_name;
$amounts[] = (float) $bid->total_freight_charge;
$rank = $rankMap[$bid->id];
$ranks[] = $rank;
$colors[] = match ($rank) {
1 => '#FFD700',
2 => '#C0C0C0',
3 => '#CD7F32',
default => '#2563EB',
};
}
return [
'datasets' => [
[
'label' => 'Freight Charge',
'data' => $amounts,
'rankData' => $ranks,
'borderColor' => '#2563EB',
'backgroundColor' => $colors,
'pointBackgroundColor' => $colors,
'pointBorderColor' => '#000',
'pointRadius' => 7,
'pointHoverRadius' => 11,
'borderWidth' => 3,
'tension' => 0.45,
'fill' => false,
],
],
'labels' => $labels,
];
}
protected function getOptions(): array
{
return [
'plugins' => [
'datalabels' => [
'anchor' => 'start',
'align' => 'start',
'offset' => -15,
'color' => '#000',
'font' => [
'weight' => 'bold',
],
'formatter' => Js::from("function(value) { return Number(value); }"),
],
],
'scales' => [
'y' => [
'beginAtZero' => true,
'ticks' => [
'stepSize' => 0.5,
],
],
],
];
}
protected function getType(): string
{
return 'bar';
}
}

View File

@@ -913,6 +913,13 @@ class PdfController extends Controller
$itemCharacteristicId = $request->query('item_characteristic_id');
$stickerId = trim($stickerId);
//dd($plantId,$itemCharacteristicId,$stickerId);
// Normalize "empty" or "" to null
$plantId = ($plantId && $plantId != 'empty') ? $plantId : null;
$itemCharacteristicId = ($itemCharacteristicId && $itemCharacteristicId != 'empty') ? $itemCharacteristicId : null;
if ($plantId && $itemCharacteristicId)
{
$plantId = $request->query('plant_id');
@@ -951,4 +958,91 @@ class PdfController extends Controller
return $pdfService->generate($stickerId, $elements->toArray());
}
}
// public function generatePdf(Request $request, $stickerId)
// {
// $plantId = $request->query('plant_id');
// $itemCharacteristicId = $request->query('item_characteristic_id');
// $stickerId = trim($stickerId);
// //dd($plantId,$itemCharacteristicId,$stickerId);
// // Normalize "empty" or "" to null
// $plantId = ($plantId && $plantId != 'empty') ? $plantId : null;
// $itemCharacteristicId = ($itemCharacteristicId && $itemCharacteristicId != 'empty') ? $itemCharacteristicId : null;
// if ($plantId && $itemCharacteristicId)
// {
// $plantId = $request->query('plant_id');
// $itemCharacteristicId = $request->query('item_characteristic_id');
// $sticId = StickerStructureDetail::where('id', $stickerId)->first();
// $sId = $sticId->id;
// $stickerId = $sticId->sticker_id;
// $dynamicElements = StickerDetail::where('sticker_structure_detail_id', $sId)
// ->where('element_type', 'Dynamic')
// ->get();
// $itemCharacteristic = null;
// if ($plantId && $itemCharacteristicId) {
// $itemCharacteristic = ItemCharacteristic::where('plant_id', $plantId)
// ->where('id', $itemCharacteristicId)
// ->first();
// }
// $pdfService = new StickerPdfService();
// return $pdfService->generatePdf1(
// $stickerId,
// $dynamicElements,
// $itemCharacteristic
// );
// }
// else
// {
// $elements = StickerStructureDetail::where('sticker_id', $stickerId)
// ->first();
// $pdfService = new StickerPdfService();
// return $pdfService->generate($stickerId, $elements->toArray());
// }
// }
public function generatePdf(Request $request, $stickerId)
{
$plantId = $request->query('plant_id');
$itemCharacteristicId = $request->query('item_characteristic_id');
$serialNumber = $request->query('serial_number');
if ($plantId && $itemCharacteristicId) {
$structure = StickerStructureDetail::findOrFail($stickerId);
$dynamicElements = StickerDetail::where(
'sticker_structure_detail_id',
$structure->id
)->where('element_type', 'Dynamic')->get();
$itemCharacteristic = ItemCharacteristic::where('plant_id', $plantId)
->where('id', $itemCharacteristicId)
->first();
return (new StickerPdfService())->generatePdf1(
$structure->sticker_id,
$dynamicElements,
$itemCharacteristic,
$serialNumber
);
}
return abort(404);
}
}

482
app/Livewire/ChatBot.php Normal file
View File

@@ -0,0 +1,482 @@
<?php
namespace App\Livewire;
use App\Services\ChatbotService;
use App\Services\GeminiChatbotService;
use Livewire\Component;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ChatBot extends Component
{
// ── Panel state ───────────────────────────────────────────────────────────
public bool $isOpen = false;
/**
* 'select' mode-picker screen shown first
* 'basic' structured query UI (production or invoice report)
* 'advanced' free-text natural-language UI (Gemini-powered)
*/
public string $mode = 'select';
// ── Basic mode — shared ───────────────────────────────────────────────────
/**
* Which report the user picked inside basic mode.
* '' report-type picker shown
* 'production' production form
* 'invoice' invoice type-lookup form
* 'invoice_status' invoice scan-status form
*/
public string $reportType = '';
public array $plants = [];
// ── Basic mode — Production report ───────────────────────────────────────
public string $result = '';
public bool $hasResult = false;
public ?int $selectedPlantId = null;
public ?int $selectedLineId = null;
public string $dateFrom = '';
public string $dateTo = '';
public array $lines = [];
// ── Basic mode — Invoice report (type lookup) ─────────────────────────────
public ?int $invoicePlantId = null;
public string $invoiceItemCode = '';
public string $invoiceResult = '';
public bool $hasInvoiceResult = false;
// ── Basic mode — Invoice status (scan status) ─────────────────────────────
public string $invoiceNumber = '';
public string $invoiceStatusResult = ''; // kept for simple error strings
public bool $hasInvoiceStatusResult = false;
/**
* Structured result from ChatbotService::getInvoiceData().
* Shape: type, message, invoice_number, total, scanned, not_scanned, unscanned_serials[]
*/
public array $invoiceStatusData = [];
/** Controls whether all unscanned serials are shown (vs the first 10). */
public bool $showAllUnscanned = false;
// ── Advanced mode ─────────────────────────────────────────────────────────
public string $advancedQuestion = '';
public string $advancedResult = '';
public bool $hasAdvancedResult = false;
public bool $isAdvancedLoading = false;
/**
* Conversation history shown in advanced mode.
* Each entry: ['role' => 'user'|'assistant', 'content' => '…']
*
* The full history is passed to GeminiChatbotService on every turn so
* Gemini can resolve follow-up messages (e.g. answering a clarification
* question) in context.
*/
public array $chatHistory = [];
// ─────────────────────────────────────────────────────────────────────────
public function mount(): void
{
$this->plants = DB::table('plants')
->whereNull('deleted_at')
->orderBy('name')
->get(['id', 'name'])
->toArray();
$this->dateFrom = now()->startOfMonth()->format('Y-m-d');
$this->dateTo = now()->format('Y-m-d');
}
// ── Mode switching ────────────────────────────────────────────────────────
public function setMode(string $mode): void
{
$this->mode = $mode;
}
public function setReportType(string $type): void
{
$this->reportType = $type;
// Clear previous results when switching report type
$this->result = '';
$this->hasResult = false;
$this->invoiceResult = '';
$this->hasInvoiceResult = false;
$this->invoiceStatusResult = '';
$this->hasInvoiceStatusResult = false;
$this->invoiceStatusData = [];
$this->showAllUnscanned = false;
}
// ── Basic mode — Production helpers ──────────────────────────────────────
public function updatedSelectedPlantId(): void
{
$this->selectedLineId = null;
$this->lines = [];
$this->result = '';
$this->hasResult = false;
if ($this->selectedPlantId) {
$this->lines = DB::table('lines')
->whereNull('deleted_at')
->where('plant_id', $this->selectedPlantId)
->orderBy('name')
->get(['id', 'name'])
->toArray();
}
}
public function updatedSelectedLineId(): void
{
$this->result = '';
$this->hasResult = false;
}
public function fetchProduction(): void
{
if (! $this->selectedPlantId) {
$this->result = 'Please select a plant.';
$this->hasResult = true;
return;
}
$query = DB::table('production_quantities')
->whereNull('deleted_at')
->where('plant_id', $this->selectedPlantId)
->whereDate('created_at', '>=', $this->dateFrom)
->whereDate('created_at', '<=', $this->dateTo);
if ($this->selectedLineId) {
$query->where('line_id', $this->selectedLineId);
}
$count = $query->count();
$plantName = collect($this->plants)
->firstWhere('id', $this->selectedPlantId)?->name ?? 'Unknown Plant';
$lineName = $this->selectedLineId
? (collect($this->lines)->firstWhere('id', $this->selectedLineId)?->name ?? 'Unknown Line')
: 'All Lines';
$from = \Carbon\Carbon::parse($this->dateFrom)->format('d M Y');
$to = \Carbon\Carbon::parse($this->dateTo)->format('d M Y');
$this->result = "Production count for {$plantName} / {$lineName} from {$from} to {$to}: {$count} records.";
$this->hasResult = true;
}
// ── Basic mode — Invoice report (type lookup) ─────────────────────────────
public function updatedInvoicePlantId(): void
{
$this->invoiceResult = '';
$this->hasInvoiceResult = false;
}
public function updatedInvoiceItemCode(): void
{
$this->invoiceResult = '';
$this->hasInvoiceResult = false;
}
public function fetchInvoiceReport(): void
{
if (! $this->invoicePlantId) {
$this->invoiceResult = 'Please select a plant.';
$this->hasInvoiceResult = true;
return;
}
$itemCode = trim($this->invoiceItemCode);
if ($itemCode === '') {
$this->invoiceResult = 'Please enter an item code.';
$this->hasInvoiceResult = true;
return;
}
$plantName = collect($this->plants)
->firstWhere('id', $this->invoicePlantId)?->name ?? 'Unknown Plant';
try {
$rows = DB::select("
WITH plant_item AS (
SELECT ? AS user_plant,
? AS user_item_code
),
t1 AS (
SELECT
plants.id AS plant_id,
plants.name AS plant_name,
ARRAY_AGG(items.code) AS item_codes
FROM plants
LEFT JOIN items ON plants.id = items.plant_id
GROUP BY plants.id, plants.name
),
t2 AS (
SELECT
t1.plant_id,
t1.plant_name,
CASE
WHEN plant_item.user_item_code = ANY(t1.item_codes) THEN 1
ELSE 0
END AS exists_flag
FROM t1
CROSS JOIN plant_item
WHERE t1.plant_name = plant_item.user_plant
),
t3 AS (
SELECT t2.plant_id, t2.plant_name, t2.exists_flag,
plant_item.user_item_code
FROM t2
LEFT JOIN plant_item ON plant_item.user_plant = t2.plant_name
),
t4 AS (
SELECT items.id AS item_id,
t3.plant_id, t3.plant_name, t3.exists_flag, t3.user_item_code
FROM t3
LEFT JOIN items
ON t3.plant_id = items.plant_id
AND t3.user_item_code = items.code
)
SELECT
t4.item_id,
t4.plant_id,
t4.plant_name,
t4.exists_flag,
t4.user_item_code,
COALESCE(sticker_masters.material_type, 0) AS material_type,
CASE
WHEN sticker_masters.item_id IS NULL
THEN 'no match found'
WHEN COALESCE(sticker_masters.material_type, 0) = 0
THEN 'serial invoice'
ELSE 'material invoice'
END AS invoice_description
FROM t4
LEFT JOIN sticker_masters
ON sticker_masters.plant_id = t4.plant_id
AND sticker_masters.item_id = t4.item_id
", [$plantName, $itemCode]);
} catch (\Exception $e) {
Log::error('ChatBot: invoice report query failed', [
'plant' => $plantName,
'item_code' => $itemCode,
'error' => $e->getMessage(),
]);
$this->invoiceResult = "Sorry, I couldn't fetch data. Please try again or contact support.";
$this->hasInvoiceResult = true;
return;
}
if (empty($rows)) {
$this->invoiceResult = "No data found for plant \"{$plantName}\". Please verify the plant selection.";
$this->hasInvoiceResult = true;
return;
}
$row = $rows[0];
if ((int) $row->exists_flag === 0) {
$this->invoiceResult = 'Provided item code does not exist in the item table.';
} else {
switch ($row->invoice_description) {
case 'no match found':
$this->invoiceResult = "Item not found in sticker master for the plant {$row->plant_name}.";
break;
case 'serial invoice':
$this->invoiceResult = 'It is a serial invoice item.';
break;
case 'material invoice':
$this->invoiceResult = 'It is a material invoice item.';
break;
default:
$this->invoiceResult = 'Unexpected result. Please contact support.';
}
}
$this->hasInvoiceResult = true;
}
// ── Basic mode — Invoice status (scan status) ─────────────────────────────
public function updatedInvoiceNumber(): void
{
$this->invoiceStatusResult = '';
$this->hasInvoiceStatusResult = false;
$this->invoiceStatusData = [];
$this->showAllUnscanned = false;
}
/**
* Looks up how many serials within an invoice have been scanned / not scanned.
* Stores structured data in $invoiceStatusData so the blade can render
* a "show more" serial-number list without dumping 70+ serials in one blob.
*/
public function fetchInvoiceStatus(): void
{
$invoiceNumber = trim(preg_replace('/\s+/', '', $this->invoiceNumber));
if (empty($invoiceNumber)) {
$this->invoiceStatusResult = 'Please enter a valid invoice number.';
$this->invoiceStatusData = [];
$this->showAllUnscanned = false;
$this->hasInvoiceStatusResult = true;
return;
}
try {
/** @var \App\Services\ChatbotService $service */
$service = app(\App\Services\ChatbotService::class);
$data = $service->getInvoiceData($invoiceNumber);
} catch (\Throwable $e) {
Log::error('ChatBot: invoice status fetch failed', [
'invoice' => $invoiceNumber,
'error' => $e->getMessage(),
]);
$data = [
'type' => 'error',
'message' => "Sorry, I couldn't fetch data for invoice {$invoiceNumber}. "
. 'Please try again or contact support.',
'invoice_number' => $invoiceNumber,
'total' => 0,
'scanned' => 0,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
$this->invoiceStatusData = $data;
$this->invoiceStatusResult = $data['message']; // fallback plain-text copy
$this->showAllUnscanned = false;
$this->hasInvoiceStatusResult = true;
}
/**
* Toggles the "show all / show less" state for unscanned serial numbers
* in the Basic Invoice Status result card.
*/
public function toggleShowAllUnscanned(): void
{
$this->showAllUnscanned = ! $this->showAllUnscanned;
}
// ── Advanced mode (Gemini-powered) ────────────────────────────────────────
/**
* Handles a free-text user message in advanced mode.
*
* Steps:
* 1. Appends the user message to chatHistory immediately (UI feedback).
* 2. Calls GeminiChatbotService with the full prior history for context.
* 3. Gemini classifies the intent, extracts params, and either:
* a) runs the appropriate DB query and returns the result, or
* b) returns a clarification question if intent is ambiguous.
* 4. Appends the assistant reply to chatHistory.
*/
public function askAdvanced(): void
{
$question = trim($this->advancedQuestion);
if (empty($question)) {
return;
}
// Show the user's message in the chat bubble immediately
$this->chatHistory[] = [
'role' => 'user',
'content' => $question,
];
$this->advancedQuestion = '';
$this->isAdvancedLoading = true;
try {
/** @var GeminiChatbotService $gemini */
$gemini = app(GeminiChatbotService::class);
// Pass history *without* the turn we just appended — the new user
// message is passed separately so Gemini sees it as the latest turn.
$priorHistory = array_slice($this->chatHistory, 0, -1);
$answer = $gemini->processMessage($priorHistory, $question);
} catch (\Throwable $e) {
Log::error('ChatBot: advanced ask failed', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
$answer = 'Sorry, something went wrong. Please try again.';
}
$this->chatHistory[] = [
'role' => 'assistant',
'content' => $answer,
];
$this->isAdvancedLoading = false;
}
public function clearAdvancedChat(): void
{
$this->chatHistory = [];
$this->advancedQuestion = '';
$this->isAdvancedLoading = false;
}
// ── Panel controls ────────────────────────────────────────────────────────
public function toggleChat(): void
{
$this->isOpen = ! $this->isOpen;
}
public function resetForm(): void
{
// Basic mode — shared
$this->reportType = '';
// Basic mode — production
$this->selectedPlantId = null;
$this->selectedLineId = null;
$this->lines = [];
$this->result = '';
$this->hasResult = false;
$this->dateFrom = now()->startOfMonth()->format('Y-m-d');
$this->dateTo = now()->format('Y-m-d');
// Basic mode — invoice type lookup
$this->invoicePlantId = null;
$this->invoiceItemCode = '';
$this->invoiceResult = '';
$this->hasInvoiceResult = false;
// Basic mode — invoice scan status
$this->invoiceNumber = '';
$this->invoiceStatusResult = '';
$this->hasInvoiceStatusResult = false;
$this->invoiceStatusData = [];
$this->showAllUnscanned = false;
// Advanced mode
$this->clearAdvancedChat();
// Go back to mode selector
$this->mode = 'select';
}
public function render()
{
return view('livewire.chat-bot');
}
}

View File

@@ -0,0 +1,236 @@
<?php
namespace App\Livewire;
use App\Exports\ProductionPlanExport;
use App\Models\ProductionPlan;
use App\Models\ProductionQuantity;
use Livewire\Component;
use Carbon\Carbon;
use DB;
use Maatwebsite\Excel\Facades\Excel;
class ProductionTargetPlan extends Component
{
public $plantId, $lineId, $month, $year;
public $records = [];
public $dates = [];
public $leaveDates = [];
public $productionPlanDates = '';
protected $listeners = [
'loadData' => 'loadProductionData',
'loadData1' => 'exportProductionData',
];
public function getMonthDates($month, $year)
{
$start = Carbon::createFromDate($year, $month, 1);
$days = $start->daysInMonth;
$dates = [];
for ($i = 1; $i <= $days; $i++) {
$dates[] = Carbon::createFromDate($year, $month, $i)
->format('Y-m-d');
}
return $dates;
}
public function loadProductionData($plantId, $lineId, $month, $year){
if (!$plantId || !$lineId || !$month || !$year) {
$this->records = [];
$this->dates = [];
$this->leaveDates = [];
return;
}
$this->dates = $this->getMonthDates($month, $year);
$data = ProductionPlan::query()
->join('items', 'items.id', '=', 'production_plans.item_id')
->join('lines', 'lines.id', '=', 'production_plans.line_id')
->join('plants', 'plants.id', '=', 'production_plans.plant_id')
->where('production_plans.plant_id', $plantId)
->where('production_plans.line_id', $lineId)
->whereMonth('production_plans.created_at', $month)
->whereYear('production_plans.created_at', $year)
->select(
'production_plans.created_at',
'production_plans.operator_id',
'plants.name as plant',
'items.code as item_code',
'items.description as item_description',
'lines.name as line_name',
'production_plans.leave_dates'
)
->first();
if ($data && $data->leave_dates) {
$this->leaveDates = array_map('trim', explode(',', $data->leave_dates));
}
$producedData = ProductionQuantity::selectRaw("
plant_id,
line_id,
item_id,
DATE(created_at) as prod_date,
COUNT(*) as total_qty
")
->where('plant_id', $plantId)
->where('line_id', $lineId)
->whereMonth('created_at', $month)
->whereYear('created_at', $year)
->groupBy('plant_id', 'line_id', 'item_id', DB::raw('DATE(created_at)'))
->get()
->groupBy(function ($row) {
return $row->plant_id . '_' . $row->line_id . '_' . $row->item_id;
})
->map(function ($group) {
return $group->keyBy('prod_date');
});
$this->records = ProductionPlan::query()
->join('items', 'items.id', '=', 'production_plans.item_id')
->join('lines', 'lines.id', '=', 'production_plans.line_id')
->join('plants', 'plants.id', '=', 'production_plans.plant_id')
->where('production_plans.plant_id', $plantId)
->where('production_plans.line_id', $lineId)
->whereMonth('production_plans.created_at', $month)
->whereYear('production_plans.created_at', $year)
->select(
'production_plans.item_id',
'production_plans.plant_id',
'production_plans.line_id',
'production_plans.plan_quantity',
'production_plans.working_days',
'items.code as item_code',
'items.description as item_description',
'lines.name as line_name',
'plants.name as plant_name'
)
->get()
// ->map(function ($row) use ($producedData) {
// $row = $row->toArray();
// $row['daily_target'] = ($row['working_days'] > 0)
// ? round($row['plan_quantity'] / $row['working_days'], 2)
// : 0;
// // $key = $row['plant_id'].'_'.$row['line_id'].'_'.$row['item_id'];
// // foreach ($this->dates as $date) {
// // $found = $producedData[$key][$date] ?? null;
// // $row['produced_quantity'][$date] = $found->total_qty ?? 0;
// // }
// $remainingDays = $row['working_days'];
// $pendingQty = 0;
// $row['daily_target_dynamic'] = [];
// $row['produced_quantity'] = [];
// $key = $row['plant_id'].'_'.$row['line_id'].'_'.$row['item_id'];
// foreach ($this->dates as $date) {
// $found = $producedData[$key][$date] ?? null;
// $producedQty = $found->total_qty ?? 0;
// // today's adjusted target
// $todayTarget = $baseDailyTarget;
// if ($remainingDays > 1 && $pendingQty > 0) {
// $todayTarget += $pendingQty / $remainingDays;
// }
// $row['daily_target_dynamic'][$date] = round($todayTarget, 2);
// $row['produced_quantity'][$date] = $producedQty;
// // calculate today's shortfall
// $pendingQty += ($todayTarget - $producedQty);
// if ($pendingQty < 0) {
// $pendingQty = 0;
// }
// $remainingDays--;
// }
// return $row;
// })
->map(function ($row) use ($producedData) {
$row = $row->toArray();
$remainingQty = $row['plan_quantity'];
$remainingDays = $row['working_days'];
$row['daily_target_dynamic'] = [];
$row['produced_quantity'] = [];
$key = $row['plant_id'].'_'.$row['line_id'].'_'.$row['item_id'];
foreach ($this->dates as $date) {
// Skip leave dates
if (in_array($date, $this->leaveDates)) {
$row['daily_target_dynamic'][$date] = '-';
$row['produced_quantity'][$date] = '-';
continue;
}
$todayTarget = $remainingDays > 0
? round($remainingQty / $remainingDays, 2)
: 0;
//$todayTarget = $remainingDays > 0
// ? $remainingQty / $remainingDays
// : 0;
$producedQty = isset($producedData[$key][$date])
? $producedData[$key][$date]->total_qty
: 0;
$row['daily_target_dynamic'][$date] = $todayTarget;
$row['produced_quantity'][$date] = $producedQty;
// Carry forward pending
$remainingQty -= $producedQty;
if ($remainingQty < 0) {
$remainingQty = 0;
}
$remainingDays--;
}
return $row;
})
->toArray();
}
public function exportProductionData()
{
return Excel::download(
new ProductionPlanExport($this->records, $this->dates),
'production_plan_data.xlsx'
);
}
public function render()
{
// return view('livewire.production-target-plan');
return view('livewire.production-target-plan', [
'records' => $this->records,
'dates' => $this->dates,
]);
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Livewire;
use App\Models\ProductionQuantity;
use Livewire\Component;
class StickerValidation extends Component
{
public $plantId;
public $refNumber;
public $serialNumber;
public bool $materialInvoice = false;
public $records = [];
protected $listeners = [
'refreshEmptySticker' => 'loadStickerData',
'addStickerToList' => 'loadSticker'
];
public function loadStickerData($plantId, $refNumber)
{
$this->plantId = $plantId;
$this->refNumber = $refNumber;
// $this->records = ProductionQuantity::where('plant_id', $plantId)
// ->where('production_order', $refNumber)
// ->orderBy('created_at', 'asc')
// ->get(['serial_number', 'operator_id']);
$this->records = ProductionQuantity::query()
->where('production_quantities.plant_id', $plantId)
->where('production_quantities.production_order', $refNumber)
->leftJoin(
'sticker_validations',
'sticker_validations.serial_number',
'=',
'production_quantities.serial_number'
)
->orderBy('production_quantities.created_at', 'asc')
->get([
'production_quantities.serial_number',
'production_quantities.operator_id',
'sticker_validations.status',
'sticker_validations.sticker_id',
])
->map(function ($row) {
$row->status = $row->status ?? '';
return $row;
});
//dd($this->records);
}
public function render()
{
return view('livewire.sticker-validation');
}
}

32
app/Livewire/Webcam.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class Webcam extends Component
{
public string $capturedPhoto = '';
// Called from JavaScript when a photo is taken
public function setPhoto(string $photo): void
{
$this->capturedPhoto = $photo;
// Fires a browser event that the Filament form will listen to
$this->dispatch('photo-captured', photo: $photo);
}
// Called from JavaScript when user clicks "Retake"
public function clearPhoto(): void
{
$this->capturedPhoto = '';
$this->dispatch('photo-captured', photo: '');
}
public function render()
{
return view('livewire.webcam');
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class EmployeeMaster extends Model
{
use SoftDeletes;
protected $fillable = [
'plant_id',
'name',
'code',
'department',
'designation',
'email',
'mobile_number',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
}

View File

@@ -3,20 +3,22 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class Item extends Model
{
use SoftDeletes;
protected $fillable = [
"plant_id",
'plant_id',
'line_id',
'category',
'code',
'description',
'hourly_quantity',
'uom',
'line_capacity',
];
public function plant(): BelongsTo
@@ -24,6 +26,11 @@ class Item extends Model
return $this->belongsTo(Plant::class);
}
public function line(): BelongsTo
{
return $this->belongsTo(Line::class);
}
public function stickerMasters()
{
return $this->hasMany(StickerMaster::class, 'item_id', 'id');
@@ -43,4 +50,9 @@ class Item extends Model
{
return $this->hasMany(TestingPanelReading::class);
}
public function itemCharacteristics()
{
return $this->hasMany(ItemCharacteristic::class, 'item_id', 'id');
}
}

View File

@@ -13,6 +13,7 @@ class Line extends Model
protected $fillable = [
"plant_id",
"block_id",
"name",
"type",
"group_work_center",
@@ -34,6 +35,11 @@ class Line extends Model
return $this->belongsTo(Plant::class);
}
public function block(): BelongsTo
{
return $this->belongsTo(Block::class);
}
public function testingPanelReadings()
{
return $this->hasMany(TestingPanelReading::class);

View File

@@ -102,4 +102,9 @@ class Plant extends Model
{
return $this->hasMany(User::class, 'plant_id', 'id');
}
public function itemCharacteristics()
{
return $this->hasMany(ItemCharacteristic::class, 'plant_id', 'id');
}
}

View File

@@ -12,12 +12,15 @@ class ProductionPlan extends Model
protected $fillable = [
"plant_id",
"item_id",
"shift_id",
"created_at",
"line_id",
"plan_quantity",
"production_quantity",
"operator_id",
"working_days",
"leave_dates",
];
public function plant(): BelongsTo
@@ -34,4 +37,9 @@ class ProductionPlan extends Model
{
return $this->belongsTo(Line::class);
}
public function item(): BelongsTo
{
return $this->belongsTo(Item::class);
}
}

View File

@@ -16,6 +16,7 @@ class ProductionQuantity extends Model
protected $fillable = [
"plant_id",
"machine_id",
"shift_id",
"line_id",
"item_id",
@@ -50,6 +51,11 @@ class ProductionQuantity extends Model
return $this->belongsTo(Item::class);
}
public function machine(): BelongsTo
{
return $this->belongsTo(Machine::class);
}
protected static function booted()
{
static::created(function ($productionQuantity) {

View File

@@ -0,0 +1,46 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class RequestQuotation extends Model
{
use SoftDeletes;
protected $fillable = [
'rfq_number',
'rfq_date_time',
'pickup_address',
'delivery_address',
'weight',
'volumetrice_size_inch',
'type_of_vehicle',
'special_type',
'no_of_vehicle',
'product_name',
'loading_by',
'unloading_by',
'pick_and_delivery',
'payment_term',
'paid_topay',
'require_date_time',
'transporter_name',
'total_freight_charge',
'transit_day',
'spot_rate_transport_master_id',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
public function spotRateTransportMaster(): BelongsTo
{
return $this->belongsTo(SpotRateTransportMaster::class);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use phpseclib3\Crypt\Common\Formats\Signature\Raw;
class RfqTransporterBid extends Model
{
use SoftDeletes;
protected $fillable = [
'request_quotation_id',
'transporter_name',
'total_freight_charge',
'transit_day',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
public function requestQuotation(): BelongsTo
{
return $this->belongsTo(RequestQuotation::class);
// return $this->belongsTo(RequestQuotation::class, 'request_quotation_id');
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class SpotRateTransportMaster extends Model
{
use SoftDeletes;
protected $casts = [
'user_name' => 'array',
];
protected $fillable = [
'group_name',
'user_name',
'created_at',
'updated_at',
'created_by',
'updated_by',
];
}

View File

@@ -25,12 +25,13 @@ class StickerDetail extends Model
'string_y_value',
'shape_name',
'shape_pen_size',
'curve_radius',
'shape_x1_value',
'shape_y1_value',
'shape_x2_value',
'shape_y2_value',
'image_path',
'image_type',
// 'image_path',
// 'image_type',
'image_x',
'image_y',
'image_width',

View File

@@ -8,28 +8,136 @@ use Illuminate\Database\Eloquent\SoftDeletes;
class StickerMappingMaster extends Model
{
use SoftDeletes;
use SoftDeletes;
protected $fillable = [
'plant_id',
'item_id',
'sticker1',
'sticker2',
'sticker3',
'sticker4',
'sticker5',
'item_characteristic_id',
'sticker_structure1_id',
'sticker1_machine_id',
'sticker1_print_ip',
'sticker_structure2_id',
'sticker2_machine_id',
'sticker2_print_ip',
'sticker_structure3_id',
'sticker3_machine_id',
'sticker3_print_ip',
'sticker_structure4_id',
'sticker4_machine_id',
'sticker4_print_ip',
'sticker_structure5_id',
'sticker5_machine_id',
'sticker5_print_ip',
'sticker_structure7_id',
'sticker6_machine_id',
'sticker6_print_ip',
'sticker_structure7_id',
'sticker7_machine_id',
'sticker7_print_ip',
'sticker_structure8_id',
'sticker8_machine_id',
'sticker8_print_ip',
'created_at',
'updated_at',
'created_by',
'updated_by'
'updated_by',
];
public function plant(): BelongsTo
public function plant()
{
return $this->belongsTo(Plant::class);
}
public function itemCharacteristic()
{
return $this->belongsTo(ItemCharacteristic::class);
}
public function item(): BelongsTo
{
return $this->belongsTo(Item::class);
return $this->belongsTo(Item::class, 'item_id');
}
public function sticker1Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure1_id');
}
public function sticker2Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure2_id');
}
public function sticker3Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure3_id');
}
public function sticker4Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure4_id');
}
public function sticker5Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure5_id');
}
public function sticker6Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure6_id');
}
public function sticker7Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure7_id');
}
public function sticker8Structure()
{
return $this->belongsTo(StickerStructureDetail::class, 'sticker_structure8_id');
}
// Machine relationships (per sticker)
public function sticker1Machine()
{
return $this->belongsTo(Machine::class, 'sticker1_machine_id');
}
public function sticker2Machine()
{
return $this->belongsTo(Machine::class, 'sticker2_machine_id');
}
public function sticker3Machine()
{
return $this->belongsTo(Machine::class, 'sticker3_machine_id');
}
public function sticker4Machine()
{
return $this->belongsTo(Machine::class, 'sticker4_machine_id');
}
public function sticker5Machine()
{
return $this->belongsTo(Machine::class, 'sticker5_machine_id');
}
public function sticker6Machine()
{
return $this->belongsTo(Machine::class, 'sticker6_machine_id');
}
public function sticker7Machine()
{
return $this->belongsTo(Machine::class, 'sticker7_machine_id');
}
public function sticker8Machine()
{
return $this->belongsTo(Machine::class, 'sticker8_machine_id');
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class StickerValidation extends Model
{
use SoftDeletes;
protected $fillable = [
'plant_id',
'machine_id',
'sticker_id',
'production_order',
'serial_number',
'status',
'created_by',
'updated_by',
'deleted_at',
];
public function plant()
{
return $this->belongsTo(Plant::class);
}
public function machine()
{
return $this->belongsTo(Machine::class);
}
}

View File

@@ -13,11 +13,13 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use NotificationChannels\WebPush\HasPushSubscriptions;
use NotificationChannels\WebPush\PushSubscription;
class User extends Authenticatable implements FilamentUser
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, HasRoles, Notifiable, SoftDeletes, HasSuperAdmin;
use HasFactory, HasRoles, Notifiable, SoftDeletes, HasSuperAdmin, HasPushSubscriptions;
/**
* The attributes that are mass assignable.
@@ -63,4 +65,9 @@ class User extends Authenticatable implements FilamentUser
{
return $this->belongsTo(Plant::class);
}
public function pushSubscriptions()
{
return $this->morphMany(PushSubscription::class, 'subscribable');
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class VisitorEntry extends Model
{
use SoftDeletes;
protected $fillable = [
'mobile_number',
'name',
'company',
'purpose_of_visit',
'type',
'in_time',
'out_time',
'photo',
'employee_master_id',
'number_of_person'
];
public function employeeMaster(): BelongsTo
{
return $this->belongsTo(EmployeeMaster::class);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class WebPushSubscription extends Model
{
protected $table = 'push_subscriptions';
protected $fillable = [
'subscribable_type',
'subscribable_id',
'endpoint',
'public_key',
'auth_token',
'content_encoding',
];
}

View File

@@ -0,0 +1,108 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use NotificationChannels\WebPush\WebPushMessage;
use NotificationChannels\WebPush\WebPushChannel;
class PushAlertNotification extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*/
// public function __construct()
// {
// //
// }
public $title;
public $body;
public function __construct($title, $body)
{
$this->title = $title;
$this->body = $body;
}
// public function via($notifiable)
// {
// return [WebPushChannel::class];
// }
public function via($notifiable)
{
return [
'database', // ✅ Filament toast
WebPushChannel::class // ✅ Browser / PWA push
];
}
public function toDatabase($notifiable): array
{
return [
'title' => $this->title,
'body' => $this->body,
];
}
// public function toWebPush($notifiable, $notification)
// {
// return (new WebPushMessage)
// ->title('New Alert 🚨')
// ->icon('/pwa-192x192.png')
// ->body('You have a new notification')
// ->action('Open App', 'open_app')
// ->data(['url' => '/admin']);
// }
public function toWebPush($notifiable, $notification)
{
return (new WebPushMessage)
->title($this->title)
->icon('/pwa-192x192.png')
->body($this->body)
->action('Open App', 'open_app')
->data(['url' => '/admin']);
}
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
// public function via(object $notifiable): array
// {
// return ['mail'];
// }
/**
* Get the mail representation of the notification.
*/
// public function toMail(object $notifiable): MailMessage
// {
// return (new MailMessage)
// ->line('The introduction to the notification.')
// ->action('Notification Action', url('/'))
// ->line('Thank you for using our application!');
// }
/**
* Get the array representation of the notification.
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
//
];
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\RequestQuotation;
use App\Models\User;
class RequestQuotationPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any RequestQuotation');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('view RequestQuotation');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create RequestQuotation');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('update RequestQuotation');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('delete RequestQuotation');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any RequestQuotation');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('restore RequestQuotation');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any RequestQuotation');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('replicate RequestQuotation');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder RequestQuotation');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, RequestQuotation $requestquotation): bool
{
return $user->checkPermissionTo('force-delete RequestQuotation');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any RequestQuotation');
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\RfqTransporterBid;
use App\Models\User;
class RfqTransporterBidPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any RfqTransporterBid');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('view RfqTransporterBid');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create RfqTransporterBid');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('update RfqTransporterBid');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('delete RfqTransporterBid');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any RfqTransporterBid');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('restore RfqTransporterBid');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any RfqTransporterBid');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('replicate RfqTransporterBid');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder RfqTransporterBid');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, RfqTransporterBid $rfqtransporterbid): bool
{
return $user->checkPermissionTo('force-delete RfqTransporterBid');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any RfqTransporterBid');
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\SpotRateTransportMaster;
use App\Models\User;
class SpotRateTransportMasterPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any SpotRateTransportMaster');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('view SpotRateTransportMaster');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create SpotRateTransportMaster');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('update SpotRateTransportMaster');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('delete SpotRateTransportMaster');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any SpotRateTransportMaster');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('restore SpotRateTransportMaster');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any SpotRateTransportMaster');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('replicate SpotRateTransportMaster');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder SpotRateTransportMaster');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, SpotRateTransportMaster $spotratetransportmaster): bool
{
return $user->checkPermissionTo('force-delete SpotRateTransportMaster');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any SpotRateTransportMaster');
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace App\Policies;
use Illuminate\Auth\Access\Response;
use App\Models\StickerValidation;
use App\Models\User;
class StickerValidationPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->checkPermissionTo('view-any StickerValidation');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('view StickerValidation');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->checkPermissionTo('create StickerValidation');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('update StickerValidation');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('delete StickerValidation');
}
/**
* Determine whether the user can delete any models.
*/
public function deleteAny(User $user): bool
{
return $user->checkPermissionTo('delete-any StickerValidation');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('restore StickerValidation');
}
/**
* Determine whether the user can restore any models.
*/
public function restoreAny(User $user): bool
{
return $user->checkPermissionTo('restore-any StickerValidation');
}
/**
* Determine whether the user can replicate the model.
*/
public function replicate(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('replicate StickerValidation');
}
/**
* Determine whether the user can reorder the models.
*/
public function reorder(User $user): bool
{
return $user->checkPermissionTo('reorder StickerValidation');
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, StickerValidation $stickervalidation): bool
{
return $user->checkPermissionTo('force-delete StickerValidation');
}
/**
* Determine whether the user can permanently delete any models.
*/
public function forceDeleteAny(User $user): bool
{
return $user->checkPermissionTo('force-delete-any StickerValidation');
}
}

View File

@@ -4,6 +4,7 @@ namespace App\Providers\Filament;
use Althinect\FilamentSpatieRolesPermissions\FilamentSpatieRolesPermissionsPlugin;
use App\Filament\Pages\InvoiceDashboard;
use App\Filament\Pages\NotificationSettings;
use Filament\Facades\Filament;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
@@ -28,6 +29,7 @@ use App\Filament\Auth\CustomLogin as AuthCustomLogin;
use App\Filament\Pages\CustomLogin;
use Filament\View\PanelsRenderHook;
use Filament\Support\Facades\FilamentView;
use Illuminate\Support\Facades\Blade;
class AdminPanelProvider extends PanelProvider
@@ -59,6 +61,7 @@ class AdminPanelProvider extends PanelProvider
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->pages([
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
// ->widgets([
@@ -123,6 +126,15 @@ class AdminPanelProvider extends PanelProvider
public function boot(): void
{
FilamentView::registerRenderHook('panels::body.end', function () {
if (url()->current() == config('app.url') . '/admin') {
return '<script src="' . asset('js/push.js') . '"></script>';
}
return '';
});
FilamentView::registerRenderHook('panels::head.end', function () {
// Only inject on the "home" page (or specific route)
if (url()->current() == config('app.url') . '/admin') {
@@ -149,5 +161,10 @@ class AdminPanelProvider extends PanelProvider
}
return '';
});
FilamentView::registerRenderHook(
PanelsRenderHook::BODY_END,
fn (): string => Blade::render("@livewire('chat-bot')"),
);
}
}

View File

@@ -0,0 +1,403 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* ChatbotService (Advanced Mode)
* ─────────────────────────────────────────────────────────────────────────────
* Parses STRUCTURED user inputs via regex no LLM involved.
*
* HOW TO ADD A NEW COMMAND:
* 1. Add an entry to $handlers with a regex pattern and a handler method name.
* 2. Write the private handler method (receives the captured group as $value).
* 3. Add a usage example to unknownCommand() so users know about it.
*
* Pattern convention: /keyword\s*=\s*(.+)/i
* - The first capture group is the raw value after "=".
* - The handler receives it already trimmed.
*/
class ChatbotService
{
/**
* Registry of structured-command handlers.
*
* Each entry:
* 'pattern' PCRE regex; capture group 1 is the extracted value.
* 'handler' name of the private method that processes the command.
*
* For two-value commands (e.g. invoice report), group 1 and group 2 are
* both passed to the handler; single-value handlers simply ignore $value2.
*/
private array $handlers = [
[
'pattern' => '/inv(?:oice)?(?:\s*(?:number|num|no\.?))?\s*(?:=|is| |equal\s+to)\s*([^\s,\.]+)/i',
'handler' => 'handleInvoice',
],
// ── Invoice report: item type lookup ──────────────────────────────────
// Accepts patterns like:
// item = 674071 plant = Vahinie Unit 2
// item code = 674071 plant = Vahinie Unit 2
// check item 674071 for plant Vahinie Unit 2
[
'pattern' => '/item(?:\s*code)?\s*(?:=|is|:)?\s*([^\s,]+)\s+(?:for\s+)?plant\s*(?:=|is|:)?\s*(.+)/i',
'handler' => 'handleInvoiceReport',
],
// ── Add more commands here ────────────────────────────────────────────
// Example:
// [
// 'pattern' => '/^\s*serial\s*=\s*(.+)/i',
// 'handler' => 'handleSerial',
// ],
];
// ─────────────────────────────────────────────────────────────────────────
// Public entry point
// ─────────────────────────────────────────────────────────────────────────
/**
* Dispatch the user's input to the matching handler.
*/
public function ask(string $input): string
{
$input = trim($input);
foreach ($this->handlers as $entry) {
if (preg_match($entry['pattern'], $input, $matches)) {
$value = trim($matches[1] ?? '');
$value2 = trim($matches[2] ?? '');
return $this->{$entry['handler']}($value, $value2);
}
}
return $this->unknownCommand($input);
}
// ─────────────────────────────────────────────────────────────────────────
// Handler: invoice = <invoice_number>
// ─────────────────────────────────────────────────────────────────────────
/**
* Looks up scan status for an invoice number in invoice_validations.
* Returns a plain-English string (used by the Advanced / free-text path).
* Structured callers should use getInvoiceData() directly.
*/
private function handleInvoice(string $invoiceNumber, string $_unused = ''): string
{
$data = $this->getInvoiceData($invoiceNumber);
// For the plain-text path (advanced mode / ChatbotService::ask()),
// reassemble a human-readable sentence from the structured data.
if (in_array($data['type'], ['invalid', 'error', 'not_found'], true)) {
return $data['message'];
}
if ($data['type'] === 'all_scanned') {
$n = $data['total'];
$itemWord = $n === 1 ? 'serial number' : 'serial numbers';
return "For invoice number {$data['invoice_number']}, all {$n} {$itemWord} "
. ($n === 1 ? 'has' : 'have') . ' been scanned. ✅';
}
// partial or none_scanned
$total = $data['total'];
$scanned = $data['scanned'];
$notScan = $data['not_scanned'];
$inv = $data['invoice_number'];
$itemWord = $total === 1 ? 'serial number' : 'serial numbers';
if ($scanned === 0) {
$msg = "For invoice number {$inv}, there "
. ($total === 1 ? 'is' : 'are') . " {$total} {$itemWord} "
. 'and none have been scanned.';
} else {
$msg = "For invoice number {$inv}, there "
. ($total === 1 ? 'is' : 'are') . " {$total} {$itemWord} in total. "
. "Out of which {$scanned} "
. ($scanned === 1 ? 'has' : 'have') . ' been scanned and '
. "{$notScan} "
. ($notScan === 1 ? 'has' : 'have') . ' not been scanned.';
}
if (! empty($data['unscanned_serials'])) {
$msg .= ' Unscanned serial numbers are: '
. implode(', ', $data['unscanned_serials']) . '.';
}
return $msg;
}
// ─────────────────────────────────────────────────────────────────────────
// Public structured accessor — used by ChatBot (Basic mode)
// ─────────────────────────────────────────────────────────────────────────
/**
* Returns structured scan-status data for an invoice number.
*
* Return shape:
* [
* 'type' => 'all_scanned' | 'partial' | 'none_scanned'
* | 'not_found' | 'error' | 'invalid',
* 'message' => string, // one-line human summary (no serial list)
* 'invoice_number' => string,
* 'total' => int,
* 'scanned' => int,
* 'not_scanned' => int,
* 'unscanned_serials' => string[], // full list — may be large
* ]
*/
public function getInvoiceData(string $invoiceNumber): array
{
$invoiceNumber = preg_replace('/\s+/', '', $invoiceNumber);
if (empty($invoiceNumber)) {
return [
'type' => 'invalid',
'message' => 'Please provide a valid invoice number. Example: invoice = 3RA0013333',
'invoice_number' => '',
'total' => 0,
'scanned' => 0,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
try {
$rows = DB::select("
SELECT
COALESCE(scanned_status, 'not scanned') AS status,
COUNT(*) AS total_count,
STRING_AGG(
CASE
WHEN scanned_status IS NULL THEN serial_number::text
END,
', '
) AS serial_numbers_not_scanned
FROM invoice_validations
WHERE invoice_number = ?
GROUP BY scanned_status
", [$invoiceNumber]);
} catch (\Exception $e) {
Log::error('ChatbotService: invoice query failed', [
'invoice' => $invoiceNumber,
'error' => $e->getMessage(),
]);
return [
'type' => 'error',
'message' => "Sorry, I couldn't fetch data for invoice {$invoiceNumber}. "
. 'Please try again or contact support if this keeps happening.',
'invoice_number' => $invoiceNumber,
'total' => 0,
'scanned' => 0,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
if (empty($rows)) {
return [
'type' => 'not_found',
'message' => "No records found for invoice number {$invoiceNumber}. "
. 'Please double-check the invoice number and try again.',
'invoice_number' => $invoiceNumber,
'total' => 0,
'scanned' => 0,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
// ── Aggregate rows ────────────────────────────────────────────────────
$totalScanned = 0;
$totalNotScanned = 0;
$unscannedSerials = [];
foreach ($rows as $row) {
if ($row->status === 'not scanned') {
$totalNotScanned = (int) $row->total_count;
if (! empty($row->serial_numbers_not_scanned)) {
$unscannedSerials = array_values(
array_filter(
array_map('trim', explode(',', $row->serial_numbers_not_scanned))
)
);
}
} else {
$totalScanned += (int) $row->total_count;
}
}
$grandTotal = $totalScanned + $totalNotScanned;
// ── All scanned ───────────────────────────────────────────────────────
if ($totalNotScanned === 0) {
$n = $grandTotal;
$itemWord = $n === 1 ? 'serial number' : 'serial numbers';
return [
'type' => 'all_scanned',
'message' => "All {$n} {$itemWord} scanned for invoice {$invoiceNumber}. ✅",
'invoice_number' => $invoiceNumber,
'total' => $grandTotal,
'scanned' => $totalScanned,
'not_scanned' => 0,
'unscanned_serials' => [],
];
}
// ── None / partial scanned ────────────────────────────────────────────
$type = $totalScanned === 0 ? 'none_scanned' : 'partial';
$itemWord = $grandTotal === 1 ? 'serial number' : 'serial numbers';
if ($totalScanned === 0) {
$summary = "Invoice {$invoiceNumber}{$grandTotal} {$itemWord}, none scanned yet.";
} else {
$summary = "Invoice {$invoiceNumber}{$grandTotal} {$itemWord} total: "
. "{$totalScanned} scanned, {$totalNotScanned} not scanned.";
}
return [
'type' => $type,
'message' => $summary,
'invoice_number' => $invoiceNumber,
'total' => $grandTotal,
'scanned' => $totalScanned,
'not_scanned' => $totalNotScanned,
'unscanned_serials' => $unscannedSerials,
];
}
// ─────────────────────────────────────────────────────────────────────────
// Handler: item = <item_code> plant = <plant_name>
// ─────────────────────────────────────────────────────────────────────────
/**
* Determines whether an item is a serial invoice or material invoice
* for a given plant, using the sticker_masters table.
*
* @param string $itemCode Extracted item code (capture group 1)
* @param string $plantName Extracted plant name (capture group 2)
*/
private function handleInvoiceReport(string $itemCode, string $plantName): string
{
$itemCode = trim($itemCode);
$plantName = trim($plantName);
if (empty($itemCode)) {
return 'Please provide an item code. Example: item = 674071 plant = Vahinie Unit 2';
}
if (empty($plantName)) {
return 'Please provide a plant name. Example: item = 674071 plant = Vahinie Unit 2';
}
try {
$rows = DB::select("
WITH plant_item AS (
SELECT ? AS user_plant,
? AS user_item_code
),
t1 AS (
SELECT
plants.id AS plant_id,
plants.name AS plant_name,
ARRAY_AGG(items.code) AS item_codes
FROM plants
LEFT JOIN items ON plants.id = items.plant_id
GROUP BY plants.id, plants.name
),
t2 AS (
SELECT
t1.plant_id,
t1.plant_name,
CASE
WHEN plant_item.user_item_code = ANY(t1.item_codes) THEN 1
ELSE 0
END AS exists_flag
FROM t1
CROSS JOIN plant_item
WHERE t1.plant_name = plant_item.user_plant
),
t3 AS (
SELECT t2.plant_id, t2.plant_name, t2.exists_flag,
plant_item.user_item_code
FROM t2
LEFT JOIN plant_item ON plant_item.user_plant = t2.plant_name
),
t4 AS (
SELECT items.id AS item_id,
t3.plant_id, t3.plant_name, t3.exists_flag, t3.user_item_code
FROM t3
LEFT JOIN items
ON t3.plant_id = items.plant_id
AND t3.user_item_code = items.code
)
SELECT
t4.item_id,
t4.plant_id,
t4.plant_name,
t4.exists_flag,
t4.user_item_code,
COALESCE(sticker_masters.material_type, 0) AS material_type,
CASE
WHEN sticker_masters.item_id IS NULL
THEN 'no match found'
WHEN COALESCE(sticker_masters.material_type, 0) = 0
THEN 'serial invoice'
ELSE 'material invoice'
END AS invoice_description
FROM t4
LEFT JOIN sticker_masters
ON sticker_masters.plant_id = t4.plant_id
AND sticker_masters.item_id = t4.item_id
", [$plantName, $itemCode]);
} catch (\Exception $e) {
Log::error('ChatbotService: invoice report query failed', [
'plant' => $plantName,
'item_code' => $itemCode,
'error' => $e->getMessage(),
]);
return "Sorry, I couldn't fetch data for item {$itemCode} in plant {$plantName}. "
. 'Please try again or contact support.';
}
if (empty($rows)) {
return "No data found for plant \"{$plantName}\". Please check the plant name and try again.";
}
$row = $rows[0];
if ((int) $row->exists_flag === 0) {
return 'Provided item code does not exist in the item table.';
}
return match ($row->invoice_description) {
'no match found' => "Item not found in sticker master for the plant {$row->plant_name}.",
'serial invoice' => 'It is a serial invoice item.',
'material invoice' => 'It is a material invoice item.',
default => 'Unexpected result. Please contact support.',
};
}
// ─────────────────────────────────────────────────────────────────────────
// Fallback for unrecognised input
// ─────────────────────────────────────────────────────────────────────────
private function unknownCommand(string $input): string
{
return "I didn't recognise that command. Please include a supported keyword with a value after '='.\n\n"
. "• Invoice scan status:\n"
. " invoice = 3RA0013333\n"
. " what is the status of invoice = 3RA0013333\n\n"
. "• Invoice type lookup:\n"
. " item = 674071 plant = Vahinie Unit 2\n"
. " item code = 674071 plant = Vahinie Unit 2\n\n"
. 'Any sentence containing keyword = value will work.';
}
}

View File

@@ -0,0 +1,819 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
/**
* GeminiChatbotService
* ─────────────────────────────────────────────────────────────────────────────
* Powers the "Advanced" chatbot mode with plain-English understanding.
*
* FLOW:
* 1. Takes the full chat history + new user message.
* 2. Sends them to Gemini with a structured system prompt.
* 3. Gemini returns JSON: { task, params, missing, clarification }.
* 4. If task is a known, complete query runs the matching DB handler.
* 5. If task is "unknown" sends the message to Gemini again as a free-form
* conversational assistant so it can answer or ask the user what they need.
* 6. If required params are missing Gemini's clarification question is returned.
*
* SUPPORTED TASKS:
* - invoice_status scan status of an invoice number
* - invoice_report serial/material invoice type for an item + plant
* - production_report production count for a plant / line / date range
* - unknown handled via a free-form Gemini conversation turn
*
* CONFIGURATION (.env):
* GEMINI_API_KEY=your_key_here
* GEMINI_MODEL=gemini-2.5-flash-preview set whichever model your key supports
*
* HOW TO ADD A NEW TASK:
* 1. Describe it in buildSystemPrompt() under TASKS.
* 2. Add a private handle*() method below.
* 3. Add a match arm in processMessage().
*/
class GeminiChatbotService
{
private string $apiKey;
/**
* Full REST endpoint model name is part of the URL path, e.g.:
* https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview:generateContent
*
* Built in __construct() from config('services.gemini.model').
* Change GEMINI_MODEL in .env to switch models without editing code.
*/
private string $apiUrl;
public function __construct()
{
$this->apiKey = config('services.gemini.api_key', '');
$model = config('services.gemini.model', 'gemini-3-flash-preview');
$this->apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent";
}
// ─────────────────────────────────────────────────────────────────────────
// Public entry point
// ─────────────────────────────────────────────────────────────────────────
/**
* Process a user message in context of the prior conversation.
*
* @param array $chatHistory Previous turns: [['role'=>'user'|'assistant','content'=>'…'], ]
* @param string $userInput The new message just typed.
* @return string Plain-text reply to show in the chat bubble.
*/
public function processMessage(array $chatHistory, string $userInput): string
{
if (empty($this->apiKey)) {
return '⚠️ AI features are not configured. Please set GEMINI_API_KEY in your .env file.';
}
// ── Step 1: Classify the intent ───────────────────────────────────────
try {
$classification = $this->classifyWithGemini($chatHistory, $userInput);
} catch (\RuntimeException $e) {
// Surface the specific error directly in the chat bubble
return $e->getMessage();
}
$task = $classification['task'] ?? 'unknown';
$params = $classification['params'] ?? [];
$missing = $classification['missing'] ?? [];
$clarification = $classification['clarification'] ?? null;
// ── Step 2: Missing required params → ask user for them ───────────────
if (! empty($missing) && ! empty($clarification)) {
return $clarification;
}
// ── Step 3: Dispatch to the appropriate handler ───────────────────────
return match ($task) {
'invoice_status' => $this->handleInvoiceStatus($params),
'invoice_report' => $this->handleInvoiceReport($params),
'production_report' => $this->handleProductionReport($params),
// ── Unknown intent: hand off to Gemini as a free-form assistant ──
'unknown' => $this->handleUnknown($chatHistory, $userInput, $clarification),
default => $this->handleUnknown($chatHistory, $userInput, null),
};
}
// ─────────────────────────────────────────────────────────────────────────
// Gemini API calls
// ─────────────────────────────────────────────────────────────────────────
/**
* Phase 1 Classify the user's intent and extract structured params.
*
* @return array|null Parsed JSON array, or null on failure.
*/
/**
* @throws \RuntimeException with a user-facing message describing exactly what failed.
*/
private function classifyWithGemini(array $history, string $userInput): array
{
$requestBody = [
'system_instruction' => [
'parts' => [['text' => $this->buildSystemPrompt()]],
],
'contents' => $this->buildGeminiContents($history, $userInput),
'generationConfig' => [
'temperature' => 0.1,
'responseMimeType' => 'application/json',
],
];
// ── HTTP call ─────────────────────────────────────────────────────────
try {
$response = Http::withHeaders(['Content-Type' => 'application/json'])
->timeout(15)
->post($this->apiUrl . '?key=' . $this->apiKey, $requestBody);
} catch (\Exception $e) {
Log::error('GeminiChatbotService: HTTP exception', ['error' => $e->getMessage()]);
throw new \RuntimeException(
'⚠️ Could not reach the Gemini API. Check your network or firewall. ('
. $e->getMessage() . ')'
);
}
// ── HTTP-level error ──────────────────────────────────────────────────
if (! $response->successful()) {
$status = $response->status();
$body = $response->body();
Log::error('GeminiChatbotService: API HTTP error', [
'status' => $status,
'body' => $body,
]);
// Parse Google's error message when available
$googleMsg = $response->json('error.message') ?? $body;
throw new \RuntimeException(
"⚠️ Gemini API returned HTTP {$status}: {$googleMsg}"
);
}
// ── Extract text from response ────────────────────────────────────────
$text = $response->json('candidates.0.content.parts.0.text');
if (empty($text)) {
// Check for prompt-blocking
$blockReason = $response->json('promptFeedback.blockReason');
$finishReason = $response->json('candidates.0.finishReason');
Log::error('GeminiChatbotService: empty response text', [
'blockReason' => $blockReason,
'finishReason' => $finishReason,
'full' => $response->json(),
]);
$hint = $blockReason
? "prompt was blocked (reason: {$blockReason})"
: ($finishReason ? "finish reason: {$finishReason}" : 'no text returned');
throw new \RuntimeException("⚠️ Gemini returned no content — {$hint}");
}
// ── JSON decode ───────────────────────────────────────────────────────
$clean = preg_replace('/^```json\s*/i', '', trim($text));
$clean = preg_replace('/\s*```$/i', '', $clean);
$parsed = json_decode($clean, true);
if (json_last_error() !== JSON_ERROR_NONE) {
Log::error('GeminiChatbotService: JSON decode failed', ['raw' => $text]);
throw new \RuntimeException(
'⚠️ Gemini returned a non-JSON response: ' . mb_substr($text, 0, 200)
);
}
return $parsed;
}
/**
* Phase 2 (unknown task only) Ask Gemini to respond conversationally.
*
* Sends the full chat history + new user message to Gemini as a friendly
* factory-operations assistant (no JSON constraint). Gemini can ask for
* clarification, answer general questions, or guide the user to one of the
* supported tasks.
*
* @param string|null $hintFromClassification Optional clarification from the
* classification step prepended as assistant context if present.
* @return string Plain-text reply from Gemini.
*/
private function callGeminiConversational(
array $history,
string $userInput,
?string $hintFromClassification = null
): ?string {
// If the classifier already produced a good clarification question, use it
// directly and skip the second API call to save latency + quota.
if (! empty($hintFromClassification)) {
return $hintFromClassification;
}
$requestBody = [
'system_instruction' => [
'parts' => [['text' => $this->buildConversationalSystemPrompt()]],
],
'contents' => $this->buildGeminiContents($history, $userInput),
'generationConfig' => [
'temperature' => 0.7, // more natural conversational tone
'maxOutputTokens' => 400,
],
];
try {
$response = Http::withHeaders(['Content-Type' => 'application/json'])
->timeout(20)
->post($this->apiUrl . '?key=' . $this->apiKey, $requestBody);
if (! $response->successful()) {
Log::error('GeminiChatbotService: API error (conversational)', [
'status' => $response->status(),
'body' => $response->body(),
]);
return null;
}
return $response->json('candidates.0.content.parts.0.text');
} catch (\Exception $e) {
Log::error('GeminiChatbotService: exception (conversational)', ['error' => $e->getMessage()]);
return null;
}
}
// ─────────────────────────────────────────────────────────────────────────
// Prompt builders
// ─────────────────────────────────────────────────────────────────────────
/**
* System prompt for Phase 1 (classification) forces JSON output.
*/
private function buildSystemPrompt(): string
{
$today = now()->format('Y-m-d');
$startOfMonth = now()->startOfMonth()->format('Y-m-d');
return <<<PROMPT
You are a factory operations assistant that classifies plain-English user queries into structured tasks.
TASKS:
1. "invoice_status"
The user wants to check how many serial numbers in an invoice have been scanned / not scanned.
Required params: invoice_number
Examples:
- "check invoice 3RA0013333"
- "is invoice 3RA0013333 fully scanned?"
- "what's the scan status of 3RA0013333"
- "show me unscanned serials for invoice ABC123"
2. "invoice_report"
The user wants to know whether an item is a serial invoice or material invoice for a given plant.
Required params: item_code, plant_name
Examples:
- "check item 674071 for plant Vahinie Unit 2"
- "is item 500100 a serial or material invoice in Chennai plant?"
- "what type is item code 200300 at Vahinie?"
3. "production_report"
The user wants the production count for a plant and optional line over a date range.
Required params: plant_name
Optional params: line_name, date_from, date_to
Default dates: date_from = {$startOfMonth}, date_to = {$today}
Interpret relative dates: "this month", "last week", "yesterday", "today", etc.
Examples:
- "show production for Chennai plant this month"
- "how many units were produced in line 1 of Vahinie Unit 2 last week?"
- "production report for all plants from 2024-01-01 to 2024-01-31"
4. "unknown"
The query cannot be clearly matched to any of the above tasks.
Use this when the user is asking something general, greeting, asking what the bot can do,
asking a follow-up question that doesn't map to a task, or if you need more context.
In this case, set "clarification" to a friendly, helpful response it may be a question,
a helpful explanation, or guidance toward the supported tasks.
CONVERSATION CONTEXT:
Consider the full conversation history. If the previous assistant message asked a clarifying question
(e.g. "Do you mean Invoice Status or Invoice Report?") and the user is now answering that question,
classify accordingly based on the combined context.
OUTPUT FORMAT (return ONLY this JSON, no markdown fences, no extra text):
{
"task": "invoice_status | invoice_report | production_report | unknown",
"params": {
"invoice_number": "...",
"item_code": "...",
"plant_name": "...",
"line_name": "...",
"date_from": "YYYY-MM-DD",
"date_to": "YYYY-MM-DD"
},
"missing": ["list of required params that were not found in the user input"],
"clarification": "Friendly response for unknown tasks or missing-param prompts. Set to null when task is clear and params are complete."
}
RULES:
- Only include params relevant to the detected task.
- If a required param is missing, add it to "missing" and set a helpful "clarification" asking only for that missing value.
- If task is "unknown", always set "missing" to [] and put your full helpful response in "clarification".
- When task is clear and all required params are present, set "missing" to [] and "clarification" to null.
PROMPT;
}
/**
* System prompt for Phase 2 (conversational fallback) plain-text output.
*
* Used only when the classifier returns "unknown" AND produced no clarification.
*/
private function buildConversationalSystemPrompt(): string
{
return <<<PROMPT
You are a helpful factory operations assistant integrated into an internal management panel.
You can perform these tasks when the user gives you enough information:
Invoice Status check how many serial numbers in an invoice have been scanned and list any unscanned ones. Requires: invoice number.
Invoice Report find out whether an item is a serial invoice or material invoice for a given plant. Requires: item code and plant name.
Production Report get the production count for a plant, optionally filtered by line and date range. Requires: plant name.
When the user's request does not match any of the above:
- Answer general questions helpfully and concisely.
- If you need more information to perform a task, ask for only the missing detail.
- Guide the user toward one of the supported tasks when relevant.
- Keep replies short and conversational (2-4 sentences max).
- Do NOT mention JSON, APIs, or technical internals.
PROMPT;
}
/**
* Convert Livewire chat history + new user message into Gemini's contents array.
* Gemini uses "model" for the assistant role (not "assistant").
*/
private function buildGeminiContents(array $history, string $userInput): array
{
$contents = [];
// Include the last 8 turns at most to stay within token limits
foreach (array_slice($history, -8) as $msg) {
$contents[] = [
'role' => $msg['role'] === 'user' ? 'user' : 'model',
'parts' => [['text' => $msg['content']]],
];
}
$contents[] = [
'role' => 'user',
'parts' => [['text' => $userInput]],
];
return $contents;
}
// ─────────────────────────────────────────────────────────────────────────
// Task handlers
// ─────────────────────────────────────────────────────────────────────────
/**
* Invoice Status delegate to ChatbotService (regex-based, same as basic mode).
*/
private function handleInvoiceStatus(array $params): string
{
$invoiceNumber = trim(preg_replace('/\s+/', '', $params['invoice_number'] ?? ''));
if (empty($invoiceNumber)) {
return 'I need the invoice number to check the scan status. What is the invoice number?';
}
/** @var ChatbotService $svc */
$svc = app(ChatbotService::class);
return $svc->ask("invoice = {$invoiceNumber}");
}
/**
* Invoice Report resolves plant name with fuzzy matching, then runs the
* same CTE query as ChatBot::fetchInvoiceReport() directly.
*
* We bypass ChatbotService::ask() here so that resolvePlant()'s multi-strategy
* fuzzy logic is applied rather than the simpler LIKE inside ChatbotService.
*/
private function handleInvoiceReport(array $params): string
{
$itemCode = trim($params['item_code'] ?? '');
$plantName = trim($params['plant_name'] ?? '');
if (empty($itemCode)) {
return 'I need the item code to look up the invoice type. What is the item code?';
}
if (empty($plantName)) {
return 'I need the plant name to look up the invoice type. Which plant are you asking about?';
}
// ── Fuzzy-resolve the plant name ──────────────────────────────────────
$plant = $this->resolvePlant($plantName);
if ($plant === null) {
return "I couldn't find a plant matching \"{$plantName}\". "
. 'Please check the plant name and try again.';
}
// ── Run the same CTE as ChatBot::fetchInvoiceReport() ─────────────────
try {
$rows = DB::select("
WITH plant_item AS (
SELECT ? AS user_plant,
? AS user_item_code
),
t1 AS (
SELECT
plants.id AS plant_id,
plants.name AS plant_name,
ARRAY_AGG(items.code) AS item_codes
FROM plants
LEFT JOIN items ON plants.id = items.plant_id
GROUP BY plants.id, plants.name
),
t2 AS (
SELECT
t1.plant_id,
t1.plant_name,
CASE
WHEN plant_item.user_item_code = ANY(t1.item_codes) THEN 1
ELSE 0
END AS exists_flag
FROM t1
CROSS JOIN plant_item
WHERE t1.plant_name = plant_item.user_plant
),
t3 AS (
SELECT t2.plant_id, t2.plant_name, t2.exists_flag,
plant_item.user_item_code
FROM t2
LEFT JOIN plant_item ON plant_item.user_plant = t2.plant_name
),
t4 AS (
SELECT items.id AS item_id,
t3.plant_id, t3.plant_name, t3.exists_flag, t3.user_item_code
FROM t3
LEFT JOIN items
ON t3.plant_id = items.plant_id
AND t3.user_item_code = items.code
)
SELECT
t4.item_id,
t4.plant_id,
t4.plant_name,
t4.exists_flag,
t4.user_item_code,
COALESCE(sticker_masters.material_type, 0) AS material_type,
CASE
WHEN sticker_masters.item_id IS NULL
THEN 'no match found'
WHEN COALESCE(sticker_masters.material_type, 0) = 0
THEN 'serial invoice'
ELSE 'material invoice'
END AS invoice_description
FROM t4
LEFT JOIN sticker_masters
ON sticker_masters.plant_id = t4.plant_id
AND sticker_masters.item_id = t4.item_id
", [$plant->name, $itemCode]);
} catch (\Exception $e) {
Log::error('GeminiChatbotService: invoice report query failed', [
'plant' => $plant->name,
'item_code' => $itemCode,
'error' => $e->getMessage(),
]);
return "Sorry, I couldn't fetch data. Please try again or contact support.";
}
if (empty($rows)) {
return "No data found for plant \"{$plant->name}\". Please verify the plant name.";
}
$row = $rows[0];
if ((int) $row->exists_flag === 0) {
return 'The provided item code does not exist in the item table.';
}
return match ($row->invoice_description) {
'serial invoice' => 'It is a serial invoice item.',
'material invoice' => 'It is a material invoice item.',
'no match found' => "Item not found in sticker master for plant {$plant->name}.",
default => 'Unexpected result. Please contact support.',
};
}
/**
* Production Report resolves plant/line names to IDs and runs the count query.
* Mirrors ChatBot::fetchProduction() but works with plain names instead of IDs,
* using resolvePlant() for robust fuzzy matching.
*/
private function handleProductionReport(array $params): string
{
$plantName = trim($params['plant_name'] ?? '');
$lineName = trim($params['line_name'] ?? '');
$dateFrom = $params['date_from'] ?? now()->startOfMonth()->format('Y-m-d');
$dateTo = $params['date_to'] ?? now()->format('Y-m-d');
if (empty($plantName)) {
return 'I need a plant name to fetch the production report. Which plant are you asking about?';
}
// ── Fuzzy-resolve the plant name ──────────────────────────────────────
$plant = $this->resolvePlant($plantName);
if ($plant === null) {
return "I couldn't find a plant matching \"{$plantName}\". "
. 'Please check the plant name and try again.';
}
// ── Base query ────────────────────────────────────────────────────────
$query = DB::table('production_quantities')
->whereNull('deleted_at')
->where('plant_id', $plant->id)
->whereDate('created_at', '>=', $dateFrom)
->whereDate('created_at', '<=', $dateTo);
$lineLabel = 'All Lines';
// ── Optionally filter by line (fuzzy LIKE match) ──────────────────────
if (! empty($lineName)) {
$line = $this->resolveLine($lineName, $plant->id);
if ($line === null) {
return "I couldn't find a line matching \"{$lineName}\" "
. "in plant \"{$plant->name}\". Please check the line name.";
}
$query->where('line_id', $line->id);
$lineLabel = $line->name;
}
try {
$count = $query->count();
} catch (\Exception $e) {
Log::error('GeminiChatbotService: production query failed', [
'plant' => $plant->name,
'line' => $lineLabel,
'error' => $e->getMessage(),
]);
return "Sorry, I couldn't fetch production data for {$plant->name}. "
. 'Please try again or contact support.';
}
$from = \Carbon\Carbon::parse($dateFrom)->format('d M Y');
$to = \Carbon\Carbon::parse($dateTo)->format('d M Y');
return "📊 Production count for {$plant->name} / {$lineLabel} "
. "from {$from} to {$to}: {$count} records.";
}
// ─────────────────────────────────────────────────────────────────────────
// Fuzzy name resolvers
// ─────────────────────────────────────────────────────────────────────────
/**
* Resolve a user-supplied plant name to the best matching DB row.
*
* Strategy cascade (stops at first hit):
* 1. Exact case-insensitive match "ransar industries-i" == "Ransar Industries-I"
* 2. Normalised LIKE match strips hyphens/spaces, swaps I↔1
* 3. Every significant word present (LIKE) "ransar unit 2" matches "Ransar Industries Unit 2"
* 4. Best token-overlap score picks the DB row sharing the most words
*
* @return object|null stdClass with {id, name} or null if no match.
*/
private function resolvePlant(string $userInput): ?object
{
$allPlants = DB::table('plants')
->whereNull('deleted_at')
->get(['id', 'name']);
$norm = $this->normaliseForMatching($userInput);
// ── Strategy 1: exact normalised match ────────────────────────────────
foreach ($allPlants as $plant) {
if ($this->normaliseForMatching($plant->name) === $norm) {
return $plant;
}
}
// ── Strategy 2: normalised LIKE (user input contained in plant name or vice-versa) ──
foreach ($allPlants as $plant) {
$dbNorm = $this->normaliseForMatching($plant->name);
if (str_contains($dbNorm, $norm) || str_contains($norm, $dbNorm)) {
return $plant;
}
}
// ── Strategy 3: all significant user words appear in the plant name ───
$userTokens = $this->significantTokens($norm);
if (count($userTokens) >= 1) {
foreach ($allPlants as $plant) {
$dbNorm = $this->normaliseForMatching($plant->name);
$allFound = true;
foreach ($userTokens as $token) {
if (! str_contains($dbNorm, $token)) {
$allFound = false;
break;
}
}
if ($allFound) {
return $plant;
}
}
}
// ── Strategy 4: best token-overlap score ─────────────────────────────
$bestPlant = null;
$bestScore = 0;
foreach ($allPlants as $plant) {
$dbTokens = $this->significantTokens($this->normaliseForMatching($plant->name));
$shared = count(array_intersect($userTokens, $dbTokens));
// Require at least half the user tokens to match to avoid false positives
$threshold = max(1, (int) ceil(count($userTokens) / 2));
if ($shared >= $threshold && $shared > $bestScore) {
$bestScore = $shared;
$bestPlant = $plant;
}
}
return $bestPlant;
}
/**
* Resolve a user-supplied line name within a specific plant.
* Uses the same normalisation + token strategies as resolvePlant().
*
* @return object|null stdClass with {id, name} or null if no match.
*/
private function resolveLine(string $userInput, int $plantId): ?object
{
$allLines = DB::table('lines')
->whereNull('deleted_at')
->where('plant_id', $plantId)
->get(['id', 'name']);
$norm = $this->normaliseForMatching($userInput);
// Strategy 1: exact normalised
foreach ($allLines as $line) {
if ($this->normaliseForMatching($line->name) === $norm) {
return $line;
}
}
// Strategy 2: normalised LIKE
foreach ($allLines as $line) {
$dbNorm = $this->normaliseForMatching($line->name);
if (str_contains($dbNorm, $norm) || str_contains($norm, $dbNorm)) {
return $line;
}
}
// Strategy 3: all user tokens found in line name
$userTokens = $this->significantTokens($norm);
foreach ($allLines as $line) {
$dbNorm = $this->normaliseForMatching($line->name);
$allFound = true;
foreach ($userTokens as $token) {
if (! str_contains($dbNorm, $token)) {
$allFound = false;
break;
}
}
if ($allFound) {
return $line;
}
}
// Strategy 4: best token-overlap
$bestLine = null;
$bestScore = 0;
foreach ($allLines as $line) {
$dbTokens = $this->significantTokens($this->normaliseForMatching($line->name));
$shared = count(array_intersect($userTokens, $dbTokens));
$threshold = max(1, (int) ceil(count($userTokens) / 2));
if ($shared >= $threshold && $shared > $bestScore) {
$bestScore = $shared;
$bestLine = $line;
}
}
return $bestLine;
}
/**
* Normalise a plant/line name for fuzzy comparison:
* - lowercase
* - replace Roman numeral suffixes I/II/III/IV 1/2/3/4 (and vice-versa digits numerals as a canonical form)
* - collapse hyphens, underscores, extra spaces into a single space
* - strip leading/trailing whitespace
*
* Both the user input AND the DB value are passed through this before comparing,
* so the comparison is always apples-to-apples.
*/
private function normaliseForMatching(string $value): string
{
$v = strtolower($value);
// 1. Punctuation/separators → space
$v = str_replace(['-', '_', '.', ','], ' ', $v);
// 2. Split any letter→digit or digit→letter boundary with a space.
// e.g. "industries1" → "industries 1", "unit2" → "unit 2", "2unit" → "2 unit"
// This must happen BEFORE Roman numeral conversion so isolated digits are
// already separated from words.
$v = preg_replace('/([a-z])(\d)/', '$1 $2', $v);
$v = preg_replace('/(\d)([a-z])/', '$1 $2', $v);
// 3. Convert standalone Roman numerals to digits.
// Applied AFTER splitting so "industries" is never touched —
// the \b boundary ensures only whole tokens are matched.
// Order matters: longer patterns first (iii before ii before i).
$romanMap = [
'/\bviii\b/' => '8',
'/\bvii\b/' => '7',
'/\bvi\b/' => '6',
'/\biv\b/' => '4',
'/\biii\b/' => '3',
'/\bii\b/' => '2',
'/\bv\b/' => '5',
'/\bi\b/' => '1', // last — single i only after all others consumed
];
foreach ($romanMap as $pattern => $digit) {
$v = preg_replace($pattern, $digit, $v);
}
// 4. Collapse multiple spaces
$v = preg_replace('/\s+/', ' ', $v);
return trim($v);
}
/**
* Split a normalised string into significant tokens (drops noise words).
*
* @return array<string>
*/
private function significantTokens(string $normalised): array
{
$stopWords = ['and', 'the', 'of', 'for', 'at', 'in', 'a'];
$tokens = explode(' ', $normalised);
return array_values(array_filter($tokens, function (string $t) use ($stopWords) {
return strlen($t) >= 2 && ! in_array($t, $stopWords, true);
}));
}
// ─────────────────────────────────────────────────────────────────────────
/**
* Unknown task let Gemini respond conversationally.
*
* If the classification step already produced a useful clarification string
* (e.g. "Could you clarify — are you asking about scan status or invoice type?"),
* we return that directly without a second API call.
* Otherwise we hit Gemini again with a conversational system prompt.
*/
private function handleUnknown(
array $chatHistory,
string $userInput,
?string $clarificationFromClassifier
): string {
$reply = $this->callGeminiConversational(
$chatHistory,
$userInput,
$clarificationFromClassifier
);
return $reply
?? "I'm not sure I understood that. I can help you with:\n\n"
. "• Invoice Status — scan progress of an invoice\n"
. "• Invoice Report — serial vs material type for an item\n"
. "• Production Report — unit count for a plant / line\n\n"
. "What would you like to check?";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,11 @@
"althinect/filament-spatie-roles-permissions": "^2.3",
"diogogpinto/filament-auth-ui-enhancer": "^1.0",
"erag/laravel-pwa": "^1.9",
"ffhs/filament-package_ffhs_approvals": "^1.0",
"filament/filament": "^3.3",
"intervention/image": "^3.11",
"irazasyed/telegram-bot-sdk": "^3.15",
"laravel-notification-channels/webpush": "^10.4",
"laravel/framework": "^11.31",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.9",

477
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "69ede7e9877dd08efdeb795bfb6b7d29",
"content-hash": "0e64d9b0a3c4d596ff8cd51b521c0565",
"packages": [
{
"name": "alperenersoy/filament-export",
@@ -1810,6 +1810,85 @@
},
"time": "2025-10-17T16:34:55+00:00"
},
{
"name": "ffhs/filament-package_ffhs_approvals",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/ffhs/filament-package_ffhs_approvals.git",
"reference": "712475522b63bf45a9e63a649d391cfe22132818"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ffhs/filament-package_ffhs_approvals/zipball/712475522b63bf45a9e63a649d391cfe22132818",
"reference": "712475522b63bf45a9e63a649d391cfe22132818",
"shasum": ""
},
"require": {
"filament/filament": "^3.0",
"php": "^8.2",
"spatie/laravel-package-tools": "^1.15.0"
},
"require-dev": {
"larastan/larastan": "^3.0",
"laravel/pint": "^1.0",
"nunomaduro/collision": "^8.0",
"orchestra/testbench": "^9.9",
"pestphp/pest": "^3.7",
"pestphp/pest-plugin-arch": "^3.0",
"pestphp/pest-plugin-laravel": "^3.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"spatie/laravel-ray": "^1.26"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Approvals": "Ffhs\\Approvals\\Facades\\Approvals"
},
"providers": [
"Ffhs\\Approvals\\ApprovalsServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Ffhs\\Approvals\\": "src/",
"Ffhs\\Approvals\\Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kromer Luc",
"email": "luc.kromer@ffhs.ch",
"role": "Developer"
},
{
"name": "Matthew Ballou",
"email": "mballou@kirschbaumdevelopment.com",
"role": "Developer"
}
],
"description": "This is my package filament-package_ffhs_approvals",
"homepage": "https://github.com/ffhs/filament-package_ffhs_approvals",
"keywords": [
"ffhs",
"filament-package_ffhs_approvals",
"kirschbaum-development",
"laravel"
],
"support": {
"issues": "https://github.com/ffhs/filament-package_ffhs_approvals/issues",
"source": "https://github.com/ffhs/filament-package_ffhs_approvals"
},
"time": "2025-07-24T14:32:41+00:00"
},
{
"name": "filament/actions",
"version": "v3.3.45",
@@ -3076,6 +3155,72 @@
},
"time": "2025-11-13T14:57:49+00:00"
},
{
"name": "laravel-notification-channels/webpush",
"version": "10.4.0",
"source": {
"type": "git",
"url": "https://github.com/laravel-notification-channels/webpush.git",
"reference": "a504bcbdd6258091b1fafdef6ca95b0891a47c9e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel-notification-channels/webpush/zipball/a504bcbdd6258091b1fafdef6ca95b0891a47c9e",
"reference": "a504bcbdd6258091b1fafdef6ca95b0891a47c9e",
"shasum": ""
},
"require": {
"illuminate/notifications": "^11.0|^12.0",
"illuminate/support": "^11.0|^12.0",
"minishlink/web-push": "^10.0",
"php": "^8.2"
},
"require-dev": {
"larastan/larastan": "^3.1",
"laravel/pint": "^1.25",
"mockery/mockery": "^1.0",
"orchestra/testbench": "^9.2|^10.0",
"phpunit/phpunit": "^10.5|^11.5.3",
"rector/rector": "^2.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"NotificationChannels\\WebPush\\WebPushServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"NotificationChannels\\WebPush\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Cretu Eusebiu",
"email": "me@cretueusebiu.com",
"homepage": "http://cretueusebiu.com",
"role": "Developer"
},
{
"name": "Joost de Bruijn",
"email": "joost@aqualabs.nl",
"role": "Maintainer"
}
],
"description": "Web Push Notifications driver for Laravel.",
"homepage": "https://github.com/laravel-notification-channels/webpush",
"support": {
"issues": "https://github.com/laravel-notification-channels/webpush/issues",
"source": "https://github.com/laravel-notification-channels/webpush/tree/10.4.0"
},
"time": "2025-12-19T15:47:27+00:00"
},
{
"name": "laravel/framework",
"version": "v11.46.1",
@@ -4880,6 +5025,73 @@
},
"time": "2019-10-05T02:44:33+00:00"
},
{
"name": "minishlink/web-push",
"version": "v10.0.1",
"source": {
"type": "git",
"url": "https://github.com/web-push-libs/web-push-php.git",
"reference": "08463189d3501cbd78a8625c87ab6680a7397aad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/web-push-libs/web-push-php/zipball/08463189d3501cbd78a8625c87ab6680a7397aad",
"reference": "08463189d3501cbd78a8625c87ab6680a7397aad",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"guzzlehttp/guzzle": "^7.9.2",
"php": ">=8.2",
"spomky-labs/base64url": "^2.0.4",
"web-token/jwt-library": "^3.4.9|^4.0.6"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^v3.91.3",
"phpstan/phpstan": "^2.1.33",
"phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^11.5.46|^12.5.2",
"symfony/polyfill-iconv": "^1.33"
},
"suggest": {
"ext-bcmath": "Optional for performance.",
"ext-gmp": "Optional for performance."
},
"type": "library",
"autoload": {
"psr-4": {
"Minishlink\\WebPush\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Louis Lagrange",
"email": "lagrange.louis@gmail.com",
"homepage": "https://github.com/Minishlink"
}
],
"description": "Web Push library for PHP",
"homepage": "https://github.com/web-push-libs/web-push-php",
"keywords": [
"Push API",
"WebPush",
"notifications",
"push",
"web"
],
"support": {
"issues": "https://github.com/web-push-libs/web-push-php/issues",
"source": "https://github.com/web-push-libs/web-push-php/tree/v10.0.1"
},
"time": "2025-12-15T10:04:28+00:00"
},
{
"name": "monolog/monolog",
"version": "3.9.0",
@@ -7696,6 +7908,180 @@
],
"time": "2025-09-24T06:40:28+00:00"
},
{
"name": "spomky-labs/base64url",
"version": "v2.0.4",
"source": {
"type": "git",
"url": "https://github.com/Spomky-Labs/base64url.git",
"reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/7752ce931ec285da4ed1f4c5aa27e45e097be61d",
"reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.11|^0.12",
"phpstan/phpstan-beberlei-assert": "^0.11|^0.12",
"phpstan/phpstan-deprecation-rules": "^0.11|^0.12",
"phpstan/phpstan-phpunit": "^0.11|^0.12",
"phpstan/phpstan-strict-rules": "^0.11|^0.12"
},
"type": "library",
"autoload": {
"psr-4": {
"Base64Url\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Florent Morselli",
"homepage": "https://github.com/Spomky-Labs/base64url/contributors"
}
],
"description": "Base 64 URL Safe Encoding/Decoding PHP Library",
"homepage": "https://github.com/Spomky-Labs/base64url",
"keywords": [
"base64",
"rfc4648",
"safe",
"url"
],
"support": {
"issues": "https://github.com/Spomky-Labs/base64url/issues",
"source": "https://github.com/Spomky-Labs/base64url/tree/v2.0.4"
},
"funding": [
{
"url": "https://github.com/Spomky",
"type": "github"
},
{
"url": "https://www.patreon.com/FlorentMorselli",
"type": "patreon"
}
],
"time": "2020-11-03T09:10:25+00:00"
},
{
"name": "spomky-labs/pki-framework",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/Spomky-Labs/pki-framework.git",
"reference": "f0e9a548df4e3942886adc9b7830581a46334631"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/f0e9a548df4e3942886adc9b7830581a46334631",
"reference": "f0e9a548df4e3942886adc9b7830581a46334631",
"shasum": ""
},
"require": {
"brick/math": "^0.10|^0.11|^0.12|^0.13|^0.14",
"ext-mbstring": "*",
"php": ">=8.1"
},
"require-dev": {
"ekino/phpstan-banned-code": "^1.0|^2.0|^3.0",
"ext-gmp": "*",
"ext-openssl": "*",
"infection/infection": "^0.28|^0.29|^0.31",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpstan/extension-installer": "^1.3|^2.0",
"phpstan/phpstan": "^1.8|^2.0",
"phpstan/phpstan-deprecation-rules": "^1.0|^2.0",
"phpstan/phpstan-phpunit": "^1.1|^2.0",
"phpstan/phpstan-strict-rules": "^1.3|^2.0",
"phpunit/phpunit": "^10.1|^11.0|^12.0",
"rector/rector": "^1.0|^2.0",
"roave/security-advisories": "dev-latest",
"symfony/string": "^6.4|^7.0|^8.0",
"symfony/var-dumper": "^6.4|^7.0|^8.0",
"symplify/easy-coding-standard": "^12.0"
},
"suggest": {
"ext-bcmath": "For better performance (or GMP)",
"ext-gmp": "For better performance (or BCMath)",
"ext-openssl": "For OpenSSL based cyphering"
},
"type": "library",
"autoload": {
"psr-4": {
"SpomkyLabs\\Pki\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Joni Eskelinen",
"email": "jonieske@gmail.com",
"role": "Original developer"
},
{
"name": "Florent Morselli",
"email": "florent.morselli@spomky-labs.com",
"role": "Spomky-Labs PKI Framework developer"
}
],
"description": "A PHP framework for managing Public Key Infrastructures. It comprises X.509 public key certificates, attribute certificates, certification requests and certification path validation.",
"homepage": "https://github.com/spomky-labs/pki-framework",
"keywords": [
"DER",
"Private Key",
"ac",
"algorithm identifier",
"asn.1",
"asn1",
"attribute certificate",
"certificate",
"certification request",
"cryptography",
"csr",
"decrypt",
"ec",
"encrypt",
"pem",
"pkcs",
"public key",
"rsa",
"sign",
"signature",
"verify",
"x.509",
"x.690",
"x509",
"x690"
],
"support": {
"issues": "https://github.com/Spomky-Labs/pki-framework/issues",
"source": "https://github.com/Spomky-Labs/pki-framework/tree/1.4.1"
},
"funding": [
{
"url": "https://github.com/Spomky",
"type": "github"
},
{
"url": "https://www.patreon.com/FlorentMorselli",
"type": "patreon"
}
],
"time": "2025-12-20T12:57:40+00:00"
},
{
"name": "symfony/clock",
"version": "v7.3.0",
@@ -10504,6 +10890,95 @@
}
],
"time": "2024-11-21T01:49:47+00:00"
},
{
"name": "web-token/jwt-library",
"version": "4.1.3",
"source": {
"type": "git",
"url": "https://github.com/web-token/jwt-library.git",
"reference": "690d4dd47b78f423cb90457f858e4106e1deb728"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/web-token/jwt-library/zipball/690d4dd47b78f423cb90457f858e4106e1deb728",
"reference": "690d4dd47b78f423cb90457f858e4106e1deb728",
"shasum": ""
},
"require": {
"brick/math": "^0.12|^0.13|^0.14",
"php": ">=8.2",
"psr/clock": "^1.0",
"spomky-labs/pki-framework": "^1.2.1"
},
"conflict": {
"spomky-labs/jose": "*"
},
"suggest": {
"ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance",
"ext-gmp": "GMP or BCMath is highly recommended to improve the library performance",
"ext-openssl": "For key management (creation, optimization, etc.) and some algorithms (AES, RSA, ECDSA, etc.)",
"ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys",
"paragonie/sodium_compat": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys",
"spomky-labs/aes-key-wrap": "For all Key Wrapping algorithms (AxxxKW, AxxxGCMKW, PBES2-HSxxx+AyyyKW...)",
"symfony/console": "Needed to use console commands",
"symfony/http-client": "To enable JKU/X5U support."
},
"type": "library",
"autoload": {
"psr-4": {
"Jose\\Component\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Florent Morselli",
"homepage": "https://github.com/Spomky"
},
{
"name": "All contributors",
"homepage": "https://github.com/web-token/jwt-framework/contributors"
}
],
"description": "JWT library",
"homepage": "https://github.com/web-token",
"keywords": [
"JOSE",
"JWE",
"JWK",
"JWKSet",
"JWS",
"Jot",
"RFC7515",
"RFC7516",
"RFC7517",
"RFC7518",
"RFC7519",
"RFC7520",
"bundle",
"jwa",
"jwt",
"symfony"
],
"support": {
"issues": "https://github.com/web-token/jwt-library/issues",
"source": "https://github.com/web-token/jwt-library/tree/4.1.3"
},
"funding": [
{
"url": "https://github.com/Spomky",
"type": "github"
},
{
"url": "https://www.patreon.com/FlorentMorselli",
"type": "patreon"
}
],
"time": "2025-12-18T14:27:35+00:00"
}
],
"packages-dev": [

View File

@@ -18,6 +18,11 @@ return [
'token' => env('POSTMARK_TOKEN'),
],
'gemini' => [
'api_key' => env('GEMINI_API_KEY'),
'model' => env('GEMINI_MODEL', 'gemini-3-flash-preview'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),

View File

@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql1 = <<<'SQL'
ALTER TABLE sticker_details
ADD COLUMN curve_radius TEXT DEFAULT NULL
SQL;
DB::statement($sql1);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Schema::table('sticker_details', function (Blueprint $table) {
// //
// });
}
};

View File

@@ -0,0 +1,91 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE sticker_mapping_masters (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
plant_id BIGINT NOT NULL,
item_characteristic_id BIGINT DEFAULT NULL,
sticker_structure1_id BIGINT DEFAULT NULL,
sticker1_machine_id BIGINT DEFAULT NULL,
sticker1_print_ip TEXT DEFAULT NULL,
sticker_structure2_id BIGINT DEFAULT NULL,
sticker2_machine_id BIGINT DEFAULT NULL,
sticker2_print_ip TEXT DEFAULT NULL,
sticker_structure3_id BIGINT DEFAULT NULL,
sticker3_machine_id BIGINT DEFAULT NULL,
sticker3_print_ip TEXT DEFAULT NULL,
sticker_structure4_id BIGINT DEFAULT NULL,
sticker4_machine_id BIGINT DEFAULT NULL,
sticker4_print_ip TEXT DEFAULT NULL,
sticker_structure5_id BIGINT DEFAULT NULL,
sticker5_machine_id BIGINT DEFAULT NULL,
sticker5_print_ip TEXT DEFAULT NULL,
sticker_structure6_id BIGINT DEFAULT NULL,
sticker6_machine_id BIGINT DEFAULT NULL,
sticker6_print_ip TEXT DEFAULT NULL,
sticker_structure7_id BIGINT DEFAULT NULL,
sticker7_machine_id BIGINT DEFAULT NULL,
sticker7_print_ip TEXT DEFAULT NULL,
sticker_structure8_id BIGINT DEFAULT NULL,
sticker8_machine_id BIGINT DEFAULT NULL,
sticker8_print_ip TEXT DEFAULT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by TEXT DEFAULT NULL,
updated_by TEXT DEFAULT NULL,
deleted_at TIMESTAMP,
FOREIGN KEY (plant_id) REFERENCES plants(id),
FOREIGN KEY (item_characteristic_id) REFERENCES item_characteristics(id),
FOREIGN KEY (sticker_structure1_id) REFERENCES sticker_structure_details(id),
FOREIGN KEY (sticker_structure2_id) REFERENCES sticker_structure_details(id),
FOREIGN KEY (sticker_structure3_id) REFERENCES sticker_structure_details(id),
FOREIGN KEY (sticker_structure4_id) REFERENCES sticker_structure_details(id),
FOREIGN KEY (sticker_structure5_id) REFERENCES sticker_structure_details(id),
FOREIGN KEY (sticker_structure6_id) REFERENCES sticker_structure_details(id),
FOREIGN KEY (sticker_structure7_id) REFERENCES sticker_structure_details(id),
FOREIGN KEY (sticker_structure8_id) REFERENCES sticker_structure_details(id),
FOREIGN KEY (sticker1_machine_id) REFERENCES machines(id),
FOREIGN KEY (sticker2_machine_id) REFERENCES machines(id),
FOREIGN KEY (sticker3_machine_id) REFERENCES machines(id),
FOREIGN KEY (sticker4_machine_id) REFERENCES machines(id),
FOREIGN KEY (sticker5_machine_id) REFERENCES machines(id),
FOREIGN KEY (sticker6_machine_id) REFERENCES machines(id),
FOREIGN KEY (sticker7_machine_id) REFERENCES machines(id),
FOREIGN KEY (sticker8_machine_id) REFERENCES machines(id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('sticker_mapping_masters');
}
};

View File

@@ -12,23 +12,23 @@ return new class extends Migration
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE sticker_mapping_masters (
CREATE TABLE sticker_validations (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
plant_id BIGINT NOT NULL,
item_id BIGINT NOT NULL,
sticker1 TEXT DEFAULT NULL,
sticker2 TEXT DEFAULT NULL,
sticker3 TEXT DEFAULT NULL,
sticker4 TEXT DEFAULT NULL,
sticker5 TEXT DEFAULT NULL,
plant_id BIGINT NOT NULL,
machine_id BIGINT NOT NULL,
production_order TEXT DEFAULT NULL,
serial_number TEXT DEFAULT NULL,
status TEXT DEFAULT NULL,
sticker_id TEXT DEFAULT NULL
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by TEXT DEFAULT NULL,
updated_by TEXT DEFAULT NULL,
deleted_at TIMESTAMP,
FOREIGN KEY (plant_id) REFERENCES plants (id),
FOREIGN KEY (item_id) REFERENCES items(id)
FOREIGN KEY (machine_id) REFERENCES machines (id)
);
SQL;
DB::statement($sql);
@@ -39,6 +39,6 @@ return new class extends Migration
*/
public function down(): void
{
Schema::dropIfExists('sticker_mapping_masters');
Schema::dropIfExists('sticker_validations');
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('sticker_details', function (Blueprint $table) {
$table->dropColumn('image_path');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Schema::table('sticker_details', function (Blueprint $table) {
// //
// });
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('sticker_details', function (Blueprint $table) {
$table->dropColumn('image_type');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Schema::table('sticker_details', function (Blueprint $table) {
// //
// });
}
};

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE spot_rate_transport_masters (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
group_name TEXT NOT NULL,
user_name TEXT DEFAULT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by TEXT DEFAULT NULL,
updated_by TEXT DEFAULT NULL,
deleted_at TIMESTAMP
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('spot_rate_transport_masters');
}
};

View File

@@ -0,0 +1,60 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE request_quotations (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
spot_rate_transport_master_id BIGINT NOT NULL,
rfq_number TEXT NOT NULL,
rfq_date_time TIMESTAMP NOT NULL DEFAULT NOW(),
pickup_address TEXT NOT NULL,
delivery_address TEXT NOT NULL,
weight TEXT NOT NULL,
volumetrice_size_inch TEXT NOT NULL,
type_of_vehicle TEXT NOT NULL,
special_type TEXT NOT NULL,
no_of_vehicle TEXT NOT NULL,
product_name TEXT NOT NULL,
loading_by TEXT NOT NULL,
unloading_by TEXT NOT NULL,
pick_and_delivery TEXT NOT NULL,
payment_term TEXT NOT NULL,
paid_topay TEXT NOT NULL,
require_date_time TIMESTAMP NOT NULL DEFAULT NOW(),
rfq_rec_on_or_before TIMESTAMP NOT NULL DEFAULT NOW(),
transporter_name TEXT NULL,
total_freight_charge TEXT NULL,
transit_day TEXT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by TEXT DEFAULT NULL,
updated_by TEXT DEFAULT NULL,
deleted_at TIMESTAMP,
FOREIGN KEY (spot_rate_transport_master_id) REFERENCES spot_rate_transport_masters (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('request_quotations');
}
};

View File

@@ -0,0 +1,44 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE rfq_transporter_bids (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
request_quotation_id BIGINT NOT NULL,
transporter_name TEXT NULL,
total_freight_charge TEXT NULL,
transit_day TEXT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by TEXT DEFAULT NULL,
updated_by TEXT DEFAULT NULL,
deleted_at TIMESTAMP,
FOREIGN KEY (request_quotation_id) REFERENCES request_quotations(id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('rfq_transporter_bids');
}
};

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
ALTER TABLE production_plans
ADD COLUMN item_id BIGINT DEFAULT NULL,
ADD CONSTRAINT production_plans_item_id_fkey
FOREIGN KEY (item_id) REFERENCES items(id);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Schema::table('production_plans', function (Blueprint $table) {
// //
// });
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
ALTER TABLE lines
ADD COLUMN block_id BIGINT DEFAULT NULL,
ADD CONSTRAINT lines_block_id_fkey
FOREIGN KEY (block_id) REFERENCES blocks(id);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Schema::table('lines', function (Blueprint $table) {
// //
// });
}
};

View File

@@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql1 = <<<'SQL'
ALTER TABLE items
ADD COLUMN line_id BIGINT DEFAULT NULL,
ADD CONSTRAINT items_line_id_fkey
FOREIGN KEY (line_id) REFERENCES lines(id);
SQL;
DB::statement($sql1);
$sql2 = <<<'SQL'
ALTER TABLE items
ADD COLUMN line_capacity TEXT DEFAULT NULL
SQL;
DB::statement($sql2);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Schema::table('items', function (Blueprint $table) {
// //
// });
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
ALTER TABLE production_quantities
ADD COLUMN machine_id BIGINT DEFAULT NULL,
ADD CONSTRAINT production_quantities_machine_id_fkey
FOREIGN KEY (machine_id) REFERENCES machines(id);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Schema::table('production_quantities', function (Blueprint $table) {
// //
// });
}
};

View File

@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql1 = <<<'SQL'
ALTER TABLE production_plans
ADD COLUMN working_days TEXT DEFAULT NULL
SQL;
DB::statement($sql1);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Schema::table('production_plans', function (Blueprint $table) {
// //
// });
}
};

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