From 34d5c9cf592902286e5910d3c967c95badb55485 Mon Sep 17 00:00:00 2001 From: Westech Admin Date: Wed, 20 May 2026 04:15:43 +0000 Subject: [PATCH] Fix load-detail and load-update page JS, add route-planner, fix pallet_list directory --- .../load/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 175 bytes .../load/__pycache__/load.cpython-312.pyc | Bin 0 -> 1087 bytes westech_r2/fixtures/doctype.json | 36 ++--- westech_r2/page/__init__.py | 0 westech_r2/page/load-detail/__init__.py | 0 westech_r2/page/load-detail/load-detail.css | 1 + westech_r2/page/load-detail/load-detail.html | 53 ++++++++ westech_r2/page/load-detail/load-detail.js | 38 ++++++ westech_r2/page/load-detail/load_detail.css | 1 + westech_r2/page/load-detail/load_detail.js | 1 + westech_r2/page/load-detail/load_detail.json | 18 +++ westech_r2/page/load-update/__init__.py | 0 westech_r2/page/load-update/load-update.html | 4 + westech_r2/page/load-update/load-update.js | 105 ++++++++++++++ westech_r2/page/load-update/load-update.py | 17 +++ westech_r2/page/load-update/load_update.css | 1 + westech_r2/page/load-update/load_update.html | 4 + westech_r2/page/load-update/load_update.js | 105 ++++++++++++++ westech_r2/page/load-update/load_update.json | 18 +++ westech_r2/page/load-update/load_update.py | 17 +++ westech_r2/page/load_detail/__init__.py | 0 westech_r2/page/load_detail/load-detail.js | 65 +++++++++ westech_r2/page/load_detail/load_detail.css | 1 + westech_r2/page/load_detail/load_detail.html | 53 ++++++++ westech_r2/page/load_detail/load_detail.js | 65 +++++++++ westech_r2/page/load_detail/load_detail.json | 18 +++ westech_r2/page/load_update/__init__.py | 0 westech_r2/page/load_update/load-update.html | 4 + westech_r2/page/load_update/load-update.js | 109 +++++++++++++++ westech_r2/page/load_update/load-update.py | 17 +++ westech_r2/page/load_update/load_update.css | 1 + westech_r2/page/load_update/load_update.html | 4 + westech_r2/page/load_update/load_update.js | 109 +++++++++++++++ westech_r2/page/load_update/load_update.json | 18 +++ westech_r2/page/load_update/load_update.py | 17 +++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 179 bytes .../__pycache__/pallet-list.cpython-312.pyc | Bin 0 -> 4720 bytes westech_r2/page/pallet_list/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 179 bytes .../__pycache__/pallet-list.cpython-312.pyc | Bin 0 -> 4720 bytes westech_r2/page/pallet_list/pallet-list.html | 82 +++++++++++ westech_r2/page/pallet_list/pallet-list.js | 128 ++++++++++++++++++ westech_r2/page/pallet_list/pallet-list.json | 19 +++ westech_r2/page/pallet_list/pallet-list.py | 64 +++++++++ westech_r2/page/pallet_list/pallet_list.html | 82 +++++++++++ westech_r2/page/pallet_list/pallet_list.js | 128 ++++++++++++++++++ westech_r2/page/pallet_list/pallet_list.json | 19 +++ westech_r2/page/pallet_list/pallet_list.py | 64 +++++++++ .../page/route-planner/route-planner.html | 4 + .../page/route-planner/route-planner.js | 38 ++++++ .../page/route-planner/route-planner.json | 9 ++ .../page/route_planner/route_planner.html | 4 + .../page/route_planner/route_planner.js | 38 ++++++ .../page/route_planner/route_planner.json | 9 ++ westech_r2/westech_r2/page/__init__.py | 0 .../page/load-detail/load-detail.json | 1 + .../page/load-detail/load_detail.json | 1 + .../westech_r2/page/load-update/__init__.py | 0 .../page/load-update/load_update.js | 7 + .../page/load-update/load_update.json | 23 ++++ .../westech_r2/page/load_detail/__init__.py | 0 .../page/load_detail/load-detail.js | 65 +++++++++ .../page/load_detail/load-detail.json | 1 + .../page/load_detail/load_detail.html | 53 ++++++++ .../page/load_detail/load_detail.js | 65 +++++++++ .../page/load_detail/load_detail.json | 23 ++++ .../westech_r2/page/load_update/__init__.py | 0 .../page/load_update/load-update.js | 109 +++++++++++++++ .../page/load_update/load_update.html | 4 + .../page/load_update/load_update.js | 109 +++++++++++++++ .../page/load_update/load_update.json | 23 ++++ .../page/load_update/load_update.py | 17 +++ .../westech_r2/page/pallet-list/__init__.py | 1 + .../page/pallet-list/pallet-list.html | 82 +++++++++++ .../page/pallet-list/pallet-list.js | 128 ++++++++++++++++++ .../page/pallet-list/pallet-list.json | 19 +++ .../page/pallet-list/pallet-list.py | 64 +++++++++ .../page/pallet_list/pallet_list.html | 82 +++++++++++ .../page/pallet_list/pallet_list.js | 128 ++++++++++++++++++ .../page/pallet_list/pallet_list.json | 19 +++ .../page/pallet_list/pallet_list.py | 64 +++++++++ .../page/route-planner/route-planner.html | 4 + .../page/route-planner/route-planner.js | 38 ++++++ .../page/route_planner/route_planner.html | 4 + .../page/route_planner/route_planner.js | 38 ++++++ 85 files changed, 2743 insertions(+), 18 deletions(-) create mode 100644 westech_r2/doctype/load/__pycache__/__init__.cpython-312.pyc create mode 100644 westech_r2/doctype/load/__pycache__/load.cpython-312.pyc create mode 100644 westech_r2/page/__init__.py create mode 100644 westech_r2/page/load-detail/__init__.py create mode 100644 westech_r2/page/load-detail/load-detail.css create mode 100644 westech_r2/page/load-detail/load-detail.html create mode 100644 westech_r2/page/load-detail/load-detail.js create mode 100644 westech_r2/page/load-detail/load_detail.css create mode 100644 westech_r2/page/load-detail/load_detail.js create mode 100644 westech_r2/page/load-detail/load_detail.json create mode 100644 westech_r2/page/load-update/__init__.py create mode 100644 westech_r2/page/load-update/load-update.html create mode 100644 westech_r2/page/load-update/load-update.js create mode 100644 westech_r2/page/load-update/load-update.py create mode 100644 westech_r2/page/load-update/load_update.css create mode 100644 westech_r2/page/load-update/load_update.html create mode 100644 westech_r2/page/load-update/load_update.js create mode 100644 westech_r2/page/load-update/load_update.json create mode 100644 westech_r2/page/load-update/load_update.py create mode 100644 westech_r2/page/load_detail/__init__.py create mode 100644 westech_r2/page/load_detail/load-detail.js create mode 100644 westech_r2/page/load_detail/load_detail.css create mode 100644 westech_r2/page/load_detail/load_detail.html create mode 100644 westech_r2/page/load_detail/load_detail.js create mode 100644 westech_r2/page/load_detail/load_detail.json create mode 100644 westech_r2/page/load_update/__init__.py create mode 100644 westech_r2/page/load_update/load-update.html create mode 100644 westech_r2/page/load_update/load-update.js create mode 100644 westech_r2/page/load_update/load-update.py create mode 100644 westech_r2/page/load_update/load_update.css create mode 100644 westech_r2/page/load_update/load_update.html create mode 100644 westech_r2/page/load_update/load_update.js create mode 100644 westech_r2/page/load_update/load_update.json create mode 100644 westech_r2/page/load_update/load_update.py create mode 100644 westech_r2/page/pallet-list/__pycache__/__init__.cpython-312.pyc create mode 100644 westech_r2/page/pallet-list/__pycache__/pallet-list.cpython-312.pyc create mode 100644 westech_r2/page/pallet_list/__init__.py create mode 100644 westech_r2/page/pallet_list/__pycache__/__init__.cpython-312.pyc create mode 100644 westech_r2/page/pallet_list/__pycache__/pallet-list.cpython-312.pyc create mode 100644 westech_r2/page/pallet_list/pallet-list.html create mode 100644 westech_r2/page/pallet_list/pallet-list.js create mode 100644 westech_r2/page/pallet_list/pallet-list.json create mode 100644 westech_r2/page/pallet_list/pallet-list.py create mode 100644 westech_r2/page/pallet_list/pallet_list.html create mode 100644 westech_r2/page/pallet_list/pallet_list.js create mode 100644 westech_r2/page/pallet_list/pallet_list.json create mode 100644 westech_r2/page/pallet_list/pallet_list.py create mode 100644 westech_r2/page/route-planner/route-planner.html create mode 100644 westech_r2/page/route-planner/route-planner.js create mode 100644 westech_r2/page/route-planner/route-planner.json create mode 100644 westech_r2/page/route_planner/route_planner.html create mode 100644 westech_r2/page/route_planner/route_planner.js create mode 100644 westech_r2/page/route_planner/route_planner.json create mode 100644 westech_r2/westech_r2/page/__init__.py create mode 100644 westech_r2/westech_r2/page/load-detail/load-detail.json create mode 100644 westech_r2/westech_r2/page/load-detail/load_detail.json create mode 100644 westech_r2/westech_r2/page/load-update/__init__.py create mode 100644 westech_r2/westech_r2/page/load-update/load_update.js create mode 100644 westech_r2/westech_r2/page/load-update/load_update.json create mode 100644 westech_r2/westech_r2/page/load_detail/__init__.py create mode 100644 westech_r2/westech_r2/page/load_detail/load-detail.js create mode 100644 westech_r2/westech_r2/page/load_detail/load-detail.json create mode 100644 westech_r2/westech_r2/page/load_detail/load_detail.html create mode 100644 westech_r2/westech_r2/page/load_detail/load_detail.js create mode 100644 westech_r2/westech_r2/page/load_detail/load_detail.json create mode 100644 westech_r2/westech_r2/page/load_update/__init__.py create mode 100644 westech_r2/westech_r2/page/load_update/load-update.js create mode 100644 westech_r2/westech_r2/page/load_update/load_update.html create mode 100644 westech_r2/westech_r2/page/load_update/load_update.js create mode 100644 westech_r2/westech_r2/page/load_update/load_update.json create mode 100644 westech_r2/westech_r2/page/load_update/load_update.py create mode 100644 westech_r2/westech_r2/page/pallet-list/__init__.py create mode 100644 westech_r2/westech_r2/page/pallet-list/pallet-list.html create mode 100644 westech_r2/westech_r2/page/pallet-list/pallet-list.js create mode 100644 westech_r2/westech_r2/page/pallet-list/pallet-list.json create mode 100644 westech_r2/westech_r2/page/pallet-list/pallet-list.py create mode 100644 westech_r2/westech_r2/page/pallet_list/pallet_list.html create mode 100644 westech_r2/westech_r2/page/pallet_list/pallet_list.js create mode 100644 westech_r2/westech_r2/page/pallet_list/pallet_list.json create mode 100644 westech_r2/westech_r2/page/pallet_list/pallet_list.py create mode 100644 westech_r2/westech_r2/page/route-planner/route-planner.html create mode 100644 westech_r2/westech_r2/page/route-planner/route-planner.js create mode 100644 westech_r2/westech_r2/page/route_planner/route_planner.html create mode 100644 westech_r2/westech_r2/page/route_planner/route_planner.js diff --git a/westech_r2/doctype/load/__pycache__/__init__.cpython-312.pyc b/westech_r2/doctype/load/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad4acfc3c0265ce8d107ad1c556ee5617944b069 GIT binary patch literal 175 zcmX@j%ge<81P}jlWP#|%AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<)@#KpPQlIY~;;_lhPbtkwwJTx;8qWyC#URE_uQdf6KYg zJVL)1=o(GLJ6_PbJcdLV0*tfgoEO7YdCXUZ3d#Y# zZdk~mkDchp=*1*LRk6ZX#N6eKouD<2@*F5w4+4v?2*6^su33l0dn{oqE+WW>RHn!? zh(qc{9OkML4Bvm$iC5H3L0x~vpY!_F&DUNnsUl&?t0@6Pxq8YF4T8V#AAW8tQSo(R zeOvcIuLKI^F0%sK)SfOX`(pm}#G|5ZCbYDn6^*n_qVr}NM{Uzi8#KCNnfa)uXASVA zmkmOb7Heguo51bMLx`148*0`jdFlpqj8*D+=n4Bm3$b2T$Pn8NcqvuQEUwzFuSBvL z-FAa*Cnm458lkSzhMhyHlr0eK_F$4p7b%6UOm&N347>g|lT~Z82LC!P_%YcPu&KGe zJh62XTddPo047&tYOQ{TLktU$h_WU{J9hpgrJH$@TCviF0!b08uu9hK#4=gc^c1*g zszj(wG+ni(FK?loU4{Syn&?f*LfH*nG*|UhQfnAWu{T6N!Bj)X;i1}7XK=VSe;gXz z@xS#Sj7;v|JPIXF5ii}Vi;g_h2!9`qHAiEIqsjeeO*vT)I&!!n?grik4oBj9v?<3o zl$HeamW)R4*5H&UBLE~|jH{#rws?B{9$Isvr yD8{?KcDKCSeLz+Oyw(s*=kkNRiHin#XpI46&w|2Vhgt&1aX(P-OdRH>J^CN(&* * * * *\n┬ ┬ ┬ ┬ ┬\n│ │ │ │ │\n│ │ │ │ └ day of week (0 - 6) (0 is Sunday)\n│ │ │ └───── month (1 - 12)\n│ │ └────────── day of month (1 - 31)\n│ └─────────────── hour (0 - 23)\n└──────────────────── minute (0 - 59)\n\n---\n\n* - Any value\n/ - Step values\n\n", + "description": "
*  *  *  *  *\n\u252c  \u252c  \u252c  \u252c  \u252c\n\u2502  \u2502  \u2502  \u2502  \u2502\n\u2502  \u2502  \u2502  \u2502  \u2514 day of week (0 - 6) (0 is Sunday)\n\u2502  \u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500 month (1 - 12)\n\u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 day of month (1 - 31)\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 hour (0 - 23)\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 minute (0 - 59)\n\n---\n\n* - Any value\n/ - Step values\n
\n", "documentation_url": null, "fetch_from": null, "fetch_if_empty": 0, @@ -267871,7 +267871,7 @@ "columns": 0, "default": null, "depends_on": "eval:doc.script_type === \"Scheduler Event\" && doc.event_frequency === 'Cron'", - "description": "
*  *  *  *  *\n┬  ┬  ┬  ┬  ┬\n│  │  │  │  │\n│  │  │  │  └ day of week (0 - 6) (0 is Sunday)\n│  │  │  └───── month (1 - 12)\n│  │  └────────── day of month (1 - 31)\n│  └─────────────── hour (0 - 23)\n└──────────────────── minute (0 - 59)\n\n---\n\n* - Any value\n/ - Step values\n
\n", + "description": "
*  *  *  *  *\n\u252c  \u252c  \u252c  \u252c  \u252c\n\u2502  \u2502  \u2502  \u2502  \u2502\n\u2502  \u2502  \u2502  \u2502  \u2514 day of week (0 - 6) (0 is Sunday)\n\u2502  \u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500 month (1 - 12)\n\u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 day of month (1 - 31)\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 hour (0 - 23)\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 minute (0 - 59)\n\n---\n\n* - Any value\n/ - Step values\n
\n", "documentation_url": null, "fetch_from": null, "fetch_if_empty": 0, @@ -475145,7 +475145,7 @@ "fetch_from": null, "fetch_if_empty": 0, "fieldname": "material_type", - "fieldtype": "Select", + "fieldtype": "Data", "hidden": 0, "hide_border": 0, "hide_days": 0, @@ -475168,7 +475168,7 @@ "non_negative": 0, "oldfieldname": null, "oldfieldtype": null, - "options": "\nChromebook / Notebook\nAll In One\nHPStream\nLaptop\nDesktop\nServer\nExternal Hard Drive\nLoose Hard Drive\nLoose SSD or mSATA Drive\nCD / Floppy / DVD / Tapes\nCell Phone / Smart Phone\nDVR\nGaming Systems\nGPS\nNetwork / Modems / Routers\nOffice/ IP Phone\nPersonal Electronics / PDA\nPOS\nPOS Terminals\nPrinters/Copiers\nPrinters/Copiers Hard Drives\nSD Cards\nSmart TV\nCRT TV\nSwitch\nTablet\nThin Clients\nUSB Drive\n# Of Pallets\nDesktops", + "options": "", "parent": "Load Item", "parentfield": "fields", "parenttype": "DocType", @@ -475529,7 +475529,7 @@ "fetch_from": null, "fetch_if_empty": 0, "fieldname": "initial_data_status", - "fieldtype": "Select", + "fieldtype": "Data", "hidden": 0, "hide_border": 0, "hide_days": 0, @@ -475552,7 +475552,7 @@ "non_negative": 0, "oldfieldname": null, "oldfieldtype": null, - "options": "\nD0\nD1\nND1\nND2\nND3\nND4\nND5", + "options": "", "parent": "Load Item", "parentfield": "fields", "parenttype": "DocType", @@ -475593,7 +475593,7 @@ "fetch_from": null, "fetch_if_empty": 0, "fieldname": "send_to", - "fieldtype": "Select", + "fieldtype": "Data", "hidden": 0, "hide_border": 0, "hide_days": 0, @@ -475616,7 +475616,7 @@ "non_negative": 0, "oldfieldname": null, "oldfieldtype": null, - "options": "\nHDR\nR2 Downstream Vendor\nShred / Degauss\nWiping\nResale\nTest\nDisassembly\nInventory", + "options": "", "parent": "Load Item", "parentfield": "fields", "parenttype": "DocType", @@ -475849,7 +475849,7 @@ "fetch_from": null, "fetch_if_empty": 0, "fieldname": "disassembly_data_status", - "fieldtype": "Select", + "fieldtype": "Data", "hidden": 0, "hide_border": 0, "hide_days": 0, @@ -475872,7 +475872,7 @@ "non_negative": 0, "oldfieldname": null, "oldfieldtype": null, - "options": "\nD0\nD1\nND1\nND2\nND3\nND4\nND5", + "options": "", "parent": "Load Item", "parentfield": "fields", "parenttype": "DocType", @@ -475913,7 +475913,7 @@ "fetch_from": null, "fetch_if_empty": 0, "fieldname": "disassembly_send_to", - "fieldtype": "Select", + "fieldtype": "Data", "hidden": 0, "hide_border": 0, "hide_days": 0, @@ -475936,7 +475936,7 @@ "non_negative": 0, "oldfieldname": null, "oldfieldtype": null, - "options": "\nHDR\nR2 Downstream Vendor\nShred / Degauss\nWiping\nResale\nTest\nDisassembly\nInventory", + "options": "", "parent": "Load Item", "parentfield": "fields", "parenttype": "DocType", @@ -476105,7 +476105,7 @@ "fetch_from": null, "fetch_if_empty": 0, "fieldname": "test_data_status", - "fieldtype": "Select", + "fieldtype": "Data", "hidden": 0, "hide_border": 0, "hide_days": 0, @@ -476128,7 +476128,7 @@ "non_negative": 0, "oldfieldname": null, "oldfieldtype": null, - "options": "\nD0\nD1\nND1\nND2\nND3\nND4\nND5", + "options": "", "parent": "Load Item", "parentfield": "fields", "parenttype": "DocType", @@ -476169,7 +476169,7 @@ "fetch_from": null, "fetch_if_empty": 0, "fieldname": "test_send_to", - "fieldtype": "Select", + "fieldtype": "Data", "hidden": 0, "hide_border": 0, "hide_days": 0, @@ -476192,7 +476192,7 @@ "non_negative": 0, "oldfieldname": null, "oldfieldtype": null, - "options": "\nHDR\nR2 Downstream Vendor\nShred / Degauss\nWiping\nResale\nTest\nDisassembly\nInventory", + "options": "", "parent": "Load Item", "parentfield": "fields", "parenttype": "DocType", diff --git a/westech_r2/page/__init__.py b/westech_r2/page/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/page/load-detail/__init__.py b/westech_r2/page/load-detail/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/page/load-detail/load-detail.css b/westech_r2/page/load-detail/load-detail.css new file mode 100644 index 0000000..f077569 --- /dev/null +++ b/westech_r2/page/load-detail/load-detail.css @@ -0,0 +1 @@ +/* CSS */ diff --git a/westech_r2/page/load-detail/load-detail.html b/westech_r2/page/load-detail/load-detail.html new file mode 100644 index 0000000..ec9f8f8 --- /dev/null +++ b/westech_r2/page/load-detail/load-detail.html @@ -0,0 +1,53 @@ +
+ + +
+

Load:

+
In Date: | Customer: | Devices: | Weight: lbs
+
+ +
+ Receiving + HDR / Disassembly + Test + R2 Downstream + Destruction +
+ + + + + + + + + + + + + + + + + + + + + + + +
Material TypeReceivingHDR / DisassemblyTestR2Destruction
CountStatusSend ToRecv'dHDD OutSend ToSanitizedStatusSend ToSentPhysHDD NeedHDD PhysHDD Logic
+
\ No newline at end of file diff --git a/westech_r2/page/load-detail/load-detail.js b/westech_r2/page/load-detail/load-detail.js new file mode 100644 index 0000000..7b02407 --- /dev/null +++ b/westech_r2/page/load-detail/load-detail.js @@ -0,0 +1,38 @@ +frappe.pages["load-detail"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Detail", + single_column: true + }); + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { showLoad(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + function showLoad(page, load) { + var h = "
"; + h += "

Load: " + load.name + "

"; + h += "

Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "

"; + h += "

Total Devices: " + (load.total_devices || 0) + "

"; + h += ""; + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item) { + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountStatusSend To
" + (item.material_type || "") + "" + (item.total_count || "") + "" + (item.initial_data_status || "") + "" + (item.send_to || "") + "
"; + $(page.body).html(h); + } +}; diff --git a/westech_r2/page/load-detail/load_detail.css b/westech_r2/page/load-detail/load_detail.css new file mode 100644 index 0000000..fd15dfe --- /dev/null +++ b/westech_r2/page/load-detail/load_detail.css @@ -0,0 +1 @@ +/* Load Detail page CSS */ diff --git a/westech_r2/page/load-detail/load_detail.js b/westech_r2/page/load-detail/load_detail.js new file mode 100644 index 0000000..af78546 --- /dev/null +++ b/westech_r2/page/load-detail/load_detail.js @@ -0,0 +1 @@ +// Load Detail page JS diff --git a/westech_r2/page/load-detail/load_detail.json b/westech_r2/page/load-detail/load_detail.json new file mode 100644 index 0000000..77dbb1d --- /dev/null +++ b/westech_r2/page/load-detail/load_detail.json @@ -0,0 +1,18 @@ +{ + "doctype": "Page", + "name": "load-detail", + "page_name": "load-detail", + "title": "Load Detail", + "page_type": "Web Page", + "module": "Westech R2", + "standard": "Yes", + "system_page": 0, + "roles": [ + { + "role": "All" + } + ], + "content": "", + "script": null, + "style": null +} \ No newline at end of file diff --git a/westech_r2/page/load-update/__init__.py b/westech_r2/page/load-update/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/page/load-update/load-update.html b/westech_r2/page/load-update/load-update.html new file mode 100644 index 0000000..6e7e05e --- /dev/null +++ b/westech_r2/page/load-update/load-update.html @@ -0,0 +1,4 @@ +
+

Load Update

+

Use the form below to update load material items.

+
diff --git a/westech_r2/page/load-update/load-update.js b/westech_r2/page/load-update/load-update.js new file mode 100644 index 0000000..ed8b54b --- /dev/null +++ b/westech_r2/page/load-update/load-update.js @@ -0,0 +1,105 @@ +frappe.pages["load-update"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Update", + single_column: true + }); + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + function loadLoad() { + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { renderForm(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + } + + function renderForm(page, load) { + var h = "
"; + h += "

Update Load: " + load.name + "

"; + h += "

Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "

"; + h += "
"; + h += ""; + h += " "; + h += " Open Form View"; + h += "
"; + + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item, idx) { + var prefix = "item_" + idx + "_"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRecv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "
"; + $(page.body).html(h); + + $("#lu-save").on("click", function() { + var items = []; + load.material_items.forEach(function(item, idx) { + var prefix = "#item_" + idx + "_"; + items.push({ + name: item.name, + total_count: parseInt($(prefix + "total_count").val()) || 0, + initial_data_status: $(prefix + "initial_data_status").val(), + send_to: $(prefix + "send_to").val(), + devices_received: parseInt($(prefix + "devices_received").val()) || 0, + hdd_removed: parseInt($(prefix + "hdd_removed").val()) || 0, + disassembly_send_to: $(prefix + "disassembly_send_to").val(), + units_sanitized_software: parseInt($(prefix + "units_sanitized_software").val()) || 0, + test_data_status: $(prefix + "test_data_status").val(), + test_send_to: $(prefix + "test_send_to").val(), + r2_units_sent: parseInt($(prefix + "r2_units_sent").val()) || 0, + units_physical_destruction: parseInt($(prefix + "units_physical_destruction").val()) || 0, + hdd_needs_sanitize: parseInt($(prefix + "hdd_needs_sanitize").val()) || 0, + hdd_physical_destruction: parseInt($(prefix + "hdd_physical_destruction").val()) || 0, + hdd_logical_sanitization: parseInt($(prefix + "hdd_logical_sanitization").val()) || 0 + }); + }); + frappe.call({ + method: "westech_r2.page.load-update.load-update.save_load_items", + args: { load_name: loadName, items: JSON.stringify(items) }, + callback: function(r) { + if (r.message && r.message.status === "ok") { + frappe.show_alert({message: "Saved", indicator: "green"}); + loadLoad(); + } else { + frappe.show_alert({message: "Save failed", indicator: "red"}); + } + } + }); + }); + + $("#lu-print").on("click", function() { + window.print(); + }); + } + + loadLoad(); +}; diff --git a/westech_r2/page/load-update/load-update.py b/westech_r2/page/load-update/load-update.py new file mode 100644 index 0000000..4afaf5e --- /dev/null +++ b/westech_r2/page/load-update/load-update.py @@ -0,0 +1,17 @@ +import frappe +import json + +@frappe.whitelist() +def save_load_items(load_name, items): + items = json.loads(items) + load_doc = frappe.get_doc("Load", load_name) + for item_data in items: + for row in load_doc.material_items: + if row.name == item_data["name"]: + for field, value in item_data.items(): + if field != "name": + row.set(field, value) + break + load_doc.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Saved " + str(len(items)) + " items"} diff --git a/westech_r2/page/load-update/load_update.css b/westech_r2/page/load-update/load_update.css new file mode 100644 index 0000000..3404ed3 --- /dev/null +++ b/westech_r2/page/load-update/load_update.css @@ -0,0 +1 @@ +/* Load Update page CSS */ diff --git a/westech_r2/page/load-update/load_update.html b/westech_r2/page/load-update/load_update.html new file mode 100644 index 0000000..6e7e05e --- /dev/null +++ b/westech_r2/page/load-update/load_update.html @@ -0,0 +1,4 @@ +
+

Load Update

+

Use the form below to update load material items.

+
diff --git a/westech_r2/page/load-update/load_update.js b/westech_r2/page/load-update/load_update.js new file mode 100644 index 0000000..ed8b54b --- /dev/null +++ b/westech_r2/page/load-update/load_update.js @@ -0,0 +1,105 @@ +frappe.pages["load-update"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Update", + single_column: true + }); + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + function loadLoad() { + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { renderForm(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + } + + function renderForm(page, load) { + var h = "
"; + h += "

Update Load: " + load.name + "

"; + h += "

Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "

"; + h += "
"; + h += ""; + h += " "; + h += " Open Form View"; + h += "
"; + + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item, idx) { + var prefix = "item_" + idx + "_"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRecv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "
"; + $(page.body).html(h); + + $("#lu-save").on("click", function() { + var items = []; + load.material_items.forEach(function(item, idx) { + var prefix = "#item_" + idx + "_"; + items.push({ + name: item.name, + total_count: parseInt($(prefix + "total_count").val()) || 0, + initial_data_status: $(prefix + "initial_data_status").val(), + send_to: $(prefix + "send_to").val(), + devices_received: parseInt($(prefix + "devices_received").val()) || 0, + hdd_removed: parseInt($(prefix + "hdd_removed").val()) || 0, + disassembly_send_to: $(prefix + "disassembly_send_to").val(), + units_sanitized_software: parseInt($(prefix + "units_sanitized_software").val()) || 0, + test_data_status: $(prefix + "test_data_status").val(), + test_send_to: $(prefix + "test_send_to").val(), + r2_units_sent: parseInt($(prefix + "r2_units_sent").val()) || 0, + units_physical_destruction: parseInt($(prefix + "units_physical_destruction").val()) || 0, + hdd_needs_sanitize: parseInt($(prefix + "hdd_needs_sanitize").val()) || 0, + hdd_physical_destruction: parseInt($(prefix + "hdd_physical_destruction").val()) || 0, + hdd_logical_sanitization: parseInt($(prefix + "hdd_logical_sanitization").val()) || 0 + }); + }); + frappe.call({ + method: "westech_r2.page.load-update.load-update.save_load_items", + args: { load_name: loadName, items: JSON.stringify(items) }, + callback: function(r) { + if (r.message && r.message.status === "ok") { + frappe.show_alert({message: "Saved", indicator: "green"}); + loadLoad(); + } else { + frappe.show_alert({message: "Save failed", indicator: "red"}); + } + } + }); + }); + + $("#lu-print").on("click", function() { + window.print(); + }); + } + + loadLoad(); +}; diff --git a/westech_r2/page/load-update/load_update.json b/westech_r2/page/load-update/load_update.json new file mode 100644 index 0000000..b5c8853 --- /dev/null +++ b/westech_r2/page/load-update/load_update.json @@ -0,0 +1,18 @@ +{ + "doctype": "Page", + "name": "load-update", + "page_name": "load-update", + "title": "Load Update", + "page_type": "Web Page", + "module": "Westech R2", + "standard": "Yes", + "system_page": 0, + "roles": [ + { + "role": "All" + } + ], + "content": "", + "script": null, + "style": null +} \ No newline at end of file diff --git a/westech_r2/page/load-update/load_update.py b/westech_r2/page/load-update/load_update.py new file mode 100644 index 0000000..4afaf5e --- /dev/null +++ b/westech_r2/page/load-update/load_update.py @@ -0,0 +1,17 @@ +import frappe +import json + +@frappe.whitelist() +def save_load_items(load_name, items): + items = json.loads(items) + load_doc = frappe.get_doc("Load", load_name) + for item_data in items: + for row in load_doc.material_items: + if row.name == item_data["name"]: + for field, value in item_data.items(): + if field != "name": + row.set(field, value) + break + load_doc.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Saved " + str(len(items)) + " items"} diff --git a/westech_r2/page/load_detail/__init__.py b/westech_r2/page/load_detail/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/page/load_detail/load-detail.js b/westech_r2/page/load_detail/load-detail.js new file mode 100644 index 0000000..b13cdca --- /dev/null +++ b/westech_r2/page/load_detail/load-detail.js @@ -0,0 +1,65 @@ +frappe.pages["load-detail"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Detail", + single_column: true + }); + + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { showLoad(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + + function showLoad(page, load) { + var h = "
"; + h += "
"; + h += "

Load: " + load.name + "

"; + h += "
In Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "
"; + h += "
Devices: " + (load.total_devices || 0) + " | Weight: " + (load.total_weight || 0) + " lbs
"; + h += "
"; + h += " "; + h += "Open Form View "; + h += "Edit Load"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item) { + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRcv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "" + (item.total_count || 0) + "" + (item.initial_data_status || "") + "" + (item.send_to || "") + "" + (item.devices_received || 0) + "" + (item.hdd_removed || 0) + "" + (item.disassembly_send_to || "") + "" + (item.units_sanitized_software || 0) + "" + (item.test_data_status || "") + "" + (item.test_send_to || "") + "" + (item.r2_units_sent || 0) + "" + (item.units_physical_destruction || 0) + "" + (item.hdd_needs_sanitize || 0) + "" + (item.hdd_physical_destruction || 0) + "" + (item.hdd_logical_sanitization || 0) + "
"; + $(page.body).html(h); + } +}; diff --git a/westech_r2/page/load_detail/load_detail.css b/westech_r2/page/load_detail/load_detail.css new file mode 100644 index 0000000..f077569 --- /dev/null +++ b/westech_r2/page/load_detail/load_detail.css @@ -0,0 +1 @@ +/* CSS */ diff --git a/westech_r2/page/load_detail/load_detail.html b/westech_r2/page/load_detail/load_detail.html new file mode 100644 index 0000000..ec9f8f8 --- /dev/null +++ b/westech_r2/page/load_detail/load_detail.html @@ -0,0 +1,53 @@ +
+ + +
+

Load:

+
In Date: | Customer: | Devices: | Weight: lbs
+
+ +
+ Receiving + HDR / Disassembly + Test + R2 Downstream + Destruction +
+ + + + + + + + + + + + + + + + + + + + + + + +
Material TypeReceivingHDR / DisassemblyTestR2Destruction
CountStatusSend ToRecv'dHDD OutSend ToSanitizedStatusSend ToSentPhysHDD NeedHDD PhysHDD Logic
+
\ No newline at end of file diff --git a/westech_r2/page/load_detail/load_detail.js b/westech_r2/page/load_detail/load_detail.js new file mode 100644 index 0000000..b13cdca --- /dev/null +++ b/westech_r2/page/load_detail/load_detail.js @@ -0,0 +1,65 @@ +frappe.pages["load-detail"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Detail", + single_column: true + }); + + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { showLoad(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + + function showLoad(page, load) { + var h = "
"; + h += "
"; + h += "

Load: " + load.name + "

"; + h += "
In Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "
"; + h += "
Devices: " + (load.total_devices || 0) + " | Weight: " + (load.total_weight || 0) + " lbs
"; + h += "
"; + h += " "; + h += "Open Form View "; + h += "Edit Load"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item) { + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRcv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "" + (item.total_count || 0) + "" + (item.initial_data_status || "") + "" + (item.send_to || "") + "" + (item.devices_received || 0) + "" + (item.hdd_removed || 0) + "" + (item.disassembly_send_to || "") + "" + (item.units_sanitized_software || 0) + "" + (item.test_data_status || "") + "" + (item.test_send_to || "") + "" + (item.r2_units_sent || 0) + "" + (item.units_physical_destruction || 0) + "" + (item.hdd_needs_sanitize || 0) + "" + (item.hdd_physical_destruction || 0) + "" + (item.hdd_logical_sanitization || 0) + "
"; + $(page.body).html(h); + } +}; diff --git a/westech_r2/page/load_detail/load_detail.json b/westech_r2/page/load_detail/load_detail.json new file mode 100644 index 0000000..77dbb1d --- /dev/null +++ b/westech_r2/page/load_detail/load_detail.json @@ -0,0 +1,18 @@ +{ + "doctype": "Page", + "name": "load-detail", + "page_name": "load-detail", + "title": "Load Detail", + "page_type": "Web Page", + "module": "Westech R2", + "standard": "Yes", + "system_page": 0, + "roles": [ + { + "role": "All" + } + ], + "content": "", + "script": null, + "style": null +} \ No newline at end of file diff --git a/westech_r2/page/load_update/__init__.py b/westech_r2/page/load_update/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/page/load_update/load-update.html b/westech_r2/page/load_update/load-update.html new file mode 100644 index 0000000..6e7e05e --- /dev/null +++ b/westech_r2/page/load_update/load-update.html @@ -0,0 +1,4 @@ +
+

Load Update

+

Use the form below to update load material items.

+
diff --git a/westech_r2/page/load_update/load-update.js b/westech_r2/page/load_update/load-update.js new file mode 100644 index 0000000..5c03738 --- /dev/null +++ b/westech_r2/page/load_update/load-update.js @@ -0,0 +1,109 @@ +frappe.pages["load-update"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Update", + single_column: true + }); + + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + function loadLoad() { + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { renderForm(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + } + + function renderForm(page, load) { + var h = "
"; + h += "

Update Load: " + load.name + "

"; + h += "

Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "

"; + h += "
"; + h += " "; + h += " "; + h += "Open Form View"; + h += "
"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item, idx) { + var prefix = "item_" + idx + "_"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRecv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "
"; + $(page.body).html(h); + + $("#lu-save").on("click", function() { + var items = []; + load.material_items.forEach(function(item, idx) { + var prefix = "#item_" + idx + "_"; + items.push({ + name: item.name, + total_count: parseInt($(prefix + "total_count").val()) || 0, + initial_data_status: $(prefix + "initial_data_status").val(), + send_to: $(prefix + "send_to").val(), + devices_received: parseInt($(prefix + "devices_received").val()) || 0, + hdd_removed: parseInt($(prefix + "hdd_removed").val()) || 0, + disassembly_send_to: $(prefix + "disassembly_send_to").val(), + units_sanitized_software: parseInt($(prefix + "units_sanitized_software").val()) || 0, + test_data_status: $(prefix + "test_data_status").val(), + test_send_to: $(prefix + "test_send_to").val(), + r2_units_sent: parseInt($(prefix + "r2_units_sent").val()) || 0, + units_physical_destruction: parseInt($(prefix + "units_physical_destruction").val()) || 0, + hdd_needs_sanitize: parseInt($(prefix + "hdd_needs_sanitize").val()) || 0, + hdd_physical_destruction: parseInt($(prefix + "hdd_physical_destruction").val()) || 0, + hdd_logical_sanitization: parseInt($(prefix + "hdd_logical_sanitization").val()) || 0 + }); + }); + frappe.call({ + method: "westech_r2.page.load-update.load-update.save_load_items", + args: { load_name: loadName, items: JSON.stringify(items) }, + callback: function(r) { + if (r.message && r.message.status === "ok") { + frappe.show_alert({message: "Saved", indicator: "green"}); + loadLoad(); + } else { + frappe.show_alert({message: "Save failed", indicator: "red"}); + } + } + }); + }); + + $("#lu-print").on("click", function() { + window.print(); + }); + } + + loadLoad(); +}; diff --git a/westech_r2/page/load_update/load-update.py b/westech_r2/page/load_update/load-update.py new file mode 100644 index 0000000..4afaf5e --- /dev/null +++ b/westech_r2/page/load_update/load-update.py @@ -0,0 +1,17 @@ +import frappe +import json + +@frappe.whitelist() +def save_load_items(load_name, items): + items = json.loads(items) + load_doc = frappe.get_doc("Load", load_name) + for item_data in items: + for row in load_doc.material_items: + if row.name == item_data["name"]: + for field, value in item_data.items(): + if field != "name": + row.set(field, value) + break + load_doc.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Saved " + str(len(items)) + " items"} diff --git a/westech_r2/page/load_update/load_update.css b/westech_r2/page/load_update/load_update.css new file mode 100644 index 0000000..3404ed3 --- /dev/null +++ b/westech_r2/page/load_update/load_update.css @@ -0,0 +1 @@ +/* Load Update page CSS */ diff --git a/westech_r2/page/load_update/load_update.html b/westech_r2/page/load_update/load_update.html new file mode 100644 index 0000000..6e7e05e --- /dev/null +++ b/westech_r2/page/load_update/load_update.html @@ -0,0 +1,4 @@ +
+

Load Update

+

Use the form below to update load material items.

+
diff --git a/westech_r2/page/load_update/load_update.js b/westech_r2/page/load_update/load_update.js new file mode 100644 index 0000000..5c03738 --- /dev/null +++ b/westech_r2/page/load_update/load_update.js @@ -0,0 +1,109 @@ +frappe.pages["load-update"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Update", + single_column: true + }); + + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + function loadLoad() { + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { renderForm(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + } + + function renderForm(page, load) { + var h = "
"; + h += "

Update Load: " + load.name + "

"; + h += "

Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "

"; + h += "
"; + h += " "; + h += " "; + h += "Open Form View"; + h += "
"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item, idx) { + var prefix = "item_" + idx + "_"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRecv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "
"; + $(page.body).html(h); + + $("#lu-save").on("click", function() { + var items = []; + load.material_items.forEach(function(item, idx) { + var prefix = "#item_" + idx + "_"; + items.push({ + name: item.name, + total_count: parseInt($(prefix + "total_count").val()) || 0, + initial_data_status: $(prefix + "initial_data_status").val(), + send_to: $(prefix + "send_to").val(), + devices_received: parseInt($(prefix + "devices_received").val()) || 0, + hdd_removed: parseInt($(prefix + "hdd_removed").val()) || 0, + disassembly_send_to: $(prefix + "disassembly_send_to").val(), + units_sanitized_software: parseInt($(prefix + "units_sanitized_software").val()) || 0, + test_data_status: $(prefix + "test_data_status").val(), + test_send_to: $(prefix + "test_send_to").val(), + r2_units_sent: parseInt($(prefix + "r2_units_sent").val()) || 0, + units_physical_destruction: parseInt($(prefix + "units_physical_destruction").val()) || 0, + hdd_needs_sanitize: parseInt($(prefix + "hdd_needs_sanitize").val()) || 0, + hdd_physical_destruction: parseInt($(prefix + "hdd_physical_destruction").val()) || 0, + hdd_logical_sanitization: parseInt($(prefix + "hdd_logical_sanitization").val()) || 0 + }); + }); + frappe.call({ + method: "westech_r2.page.load-update.load-update.save_load_items", + args: { load_name: loadName, items: JSON.stringify(items) }, + callback: function(r) { + if (r.message && r.message.status === "ok") { + frappe.show_alert({message: "Saved", indicator: "green"}); + loadLoad(); + } else { + frappe.show_alert({message: "Save failed", indicator: "red"}); + } + } + }); + }); + + $("#lu-print").on("click", function() { + window.print(); + }); + } + + loadLoad(); +}; diff --git a/westech_r2/page/load_update/load_update.json b/westech_r2/page/load_update/load_update.json new file mode 100644 index 0000000..b5c8853 --- /dev/null +++ b/westech_r2/page/load_update/load_update.json @@ -0,0 +1,18 @@ +{ + "doctype": "Page", + "name": "load-update", + "page_name": "load-update", + "title": "Load Update", + "page_type": "Web Page", + "module": "Westech R2", + "standard": "Yes", + "system_page": 0, + "roles": [ + { + "role": "All" + } + ], + "content": "", + "script": null, + "style": null +} \ No newline at end of file diff --git a/westech_r2/page/load_update/load_update.py b/westech_r2/page/load_update/load_update.py new file mode 100644 index 0000000..4afaf5e --- /dev/null +++ b/westech_r2/page/load_update/load_update.py @@ -0,0 +1,17 @@ +import frappe +import json + +@frappe.whitelist() +def save_load_items(load_name, items): + items = json.loads(items) + load_doc = frappe.get_doc("Load", load_name) + for item_data in items: + for row in load_doc.material_items: + if row.name == item_data["name"]: + for field, value in item_data.items(): + if field != "name": + row.set(field, value) + break + load_doc.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Saved " + str(len(items)) + " items"} diff --git a/westech_r2/page/pallet-list/__pycache__/__init__.cpython-312.pyc b/westech_r2/page/pallet-list/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..338fb5b851ab9b4086042205e832854d69943766 GIT binary patch literal 179 zcmX@j%ge<81j09YvXp@IV-N=&d}aZPOlPQM&}8&m$xy@u`yhT2zpiT2Z2#l$w{Ep$`-))-O*jE=f(!h%YiiW)>u-r|K6Z=H#T7=;mY=m*~gG qXXa&=#K-FuRQ}?y$<0qG%}KQ@Vg*{k2*kx8#z$sGM#ds$APWHEi7tQu literal 0 HcmV?d00001 diff --git a/westech_r2/page/pallet-list/__pycache__/pallet-list.cpython-312.pyc b/westech_r2/page/pallet-list/__pycache__/pallet-list.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b60feb25034beb7949e5061281e4e6f5aab99a2 GIT binary patch literal 4720 zcmdrPOKcn0asQRCW-rt-~8wTUn*N*t#?HKkSgqVXYP4?DdvWD>(k0-EqF#;2?IAIFy ze;<^lJk1mLa1(o%I8>gzhn1ztL#3$-Y3er4G0)Jtp%}Ao35Mp#`aKok8m8bTPs1LR z<_ncnyiCP4*rf_S(QuW+7;_7Ho&C=&aov_}`^f?TBye0HGpWIBW;?^feXr@y*C~jWm4Lf}ql9 zuCA5i%iy|exJ;D~JP%tRl(K8V@jdp}R*JJD##)uyoU_=1OLI!cc#q~R?YsRVvf5QI zVoe#-I*2n@yxH8-{#SEUN@#Wsa)-DM~d{hx4k{}DxErG9+KN`!*N;)Y>^^~>NG7WW{RmXI^SEqVm zsAQ;TKqteO{W_J(CK5W+k4A6l`?^YbeXLhKQf(G8HyC2Oy(;15)Z^b~js`~ptQQn@ zd287dfvbTV*I4h(_j*tFzwcFTvJzFYG7CF>iF?)7YGp-5T`B>JXm%jvXVtFBz-Zt~ zn7uMS6$*Es;@H87@iA73PG2*;%Dyucm|=|f6@(cvCCYQ9^-^h2;bTkQsJkci6gxiQ4@|I^f5KiFm<)GUZHOJ1WT!%t z!Kq_2EuHZ!*xqkj__hkiS|J({$Dw#>NJfUfqXI|rn}}S z%gphK+EYeR=;e%mRr_{7;EfeQ2l#J$eQLR5;)=}dZNMivy^ z7E7mi5oLi424qto=nV))5~8f=j`=x35+bogGz%rI39W>#2i+kgGmtUGed!Doylg^| z5sR%JFQ4!_tGOsnG_g)dRj=u=6Yaza?dSktzG`3hZ#A6&QOdPVwdSeT&9dR=KAwo{}-pXxS@RK(BmKFJ3|HQ_*WKZS#q=U z>>mdI6#RW~yU(BR^MCpFR^Mp8bM@0=`H!%y6uYZq59ZrHZmujNLcI$D;4OTp!_ zrLoPlB1poCYmfYwQXJc;gD~o%li(7QSIX1305N)fa77noFb+Vx%tJapIP-iFl3x?KmZ z5vB}u9Aw;r)~p^p@sQl_Ig~QlvTUR_k^VrnPGwN-IpZx4D_(RJG3_xW_P=oyM>WH=5n{Rl zR%owb1IpWs2)Bo%*8tO<#V9K^(NYhhStm*jq3*2eEjUuT0DMD8x&*VZgkn!R1Arrn z|D{kQbIxM$+cHr}79w#uozg9EcNY@@GNMM0PK%0=l%;c^NN2MHnB~l;K{}$3u z=@b|fmChr|8wmUufLxOuF-br#hT^8A07xJW@*e@9i>!Iuek^Z4wjSQHpM?9&%$6-@ z7v##(S3W=g>G_TEt)qRp!2;F3<7r zBflES+j}>uULy&imY{7u;{h0+16QDC8^yK(IJ)TXhWR;gB)Z>?JKU%ah7;~%h9aYc zytH0Srul3_cuN`v1t`Jg834N^j^kfr&L?`yhT2zpiT2Z2#l$w{Ep$`-))-O*jE=f(!h%YiiW)>u-r|K6Z=H#T7=;mY=m*~gG qXXa&=#K-FuRQ}?y$<0qG%}KQ@Vg*{k2*kx8#z$sGM#ds$APWHEi7tQu literal 0 HcmV?d00001 diff --git a/westech_r2/page/pallet_list/__pycache__/pallet-list.cpython-312.pyc b/westech_r2/page/pallet_list/__pycache__/pallet-list.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b60feb25034beb7949e5061281e4e6f5aab99a2 GIT binary patch literal 4720 zcmdrPOKcn0asQRCW-rt-~8wTUn*N*t#?HKkSgqVXYP4?DdvWD>(k0-EqF#;2?IAIFy ze;<^lJk1mLa1(o%I8>gzhn1ztL#3$-Y3er4G0)Jtp%}Ao35Mp#`aKok8m8bTPs1LR z<_ncnyiCP4*rf_S(QuW+7;_7Ho&C=&aov_}`^f?TBye0HGpWIBW;?^feXr@y*C~jWm4Lf}ql9 zuCA5i%iy|exJ;D~JP%tRl(K8V@jdp}R*JJD##)uyoU_=1OLI!cc#q~R?YsRVvf5QI zVoe#-I*2n@yxH8-{#SEUN@#Wsa)-DM~d{hx4k{}DxErG9+KN`!*N;)Y>^^~>NG7WW{RmXI^SEqVm zsAQ;TKqteO{W_J(CK5W+k4A6l`?^YbeXLhKQf(G8HyC2Oy(;15)Z^b~js`~ptQQn@ zd287dfvbTV*I4h(_j*tFzwcFTvJzFYG7CF>iF?)7YGp-5T`B>JXm%jvXVtFBz-Zt~ zn7uMS6$*Es;@H87@iA73PG2*;%Dyucm|=|f6@(cvCCYQ9^-^h2;bTkQsJkci6gxiQ4@|I^f5KiFm<)GUZHOJ1WT!%t z!Kq_2EuHZ!*xqkj__hkiS|J({$Dw#>NJfUfqXI|rn}}S z%gphK+EYeR=;e%mRr_{7;EfeQ2l#J$eQLR5;)=}dZNMivy^ z7E7mi5oLi424qto=nV))5~8f=j`=x35+bogGz%rI39W>#2i+kgGmtUGed!Doylg^| z5sR%JFQ4!_tGOsnG_g)dRj=u=6Yaza?dSktzG`3hZ#A6&QOdPVwdSeT&9dR=KAwo{}-pXxS@RK(BmKFJ3|HQ_*WKZS#q=U z>>mdI6#RW~yU(BR^MCpFR^Mp8bM@0=`H!%y6uYZq59ZrHZmujNLcI$D;4OTp!_ zrLoPlB1poCYmfYwQXJc;gD~o%li(7QSIX1305N)fa77noFb+Vx%tJapIP-iFl3x?KmZ z5vB}u9Aw;r)~p^p@sQl_Ig~QlvTUR_k^VrnPGwN-IpZx4D_(RJG3_xW_P=oyM>WH=5n{Rl zR%owb1IpWs2)Bo%*8tO<#V9K^(NYhhStm*jq3*2eEjUuT0DMD8x&*VZgkn!R1Arrn z|D{kQbIxM$+cHr}79w#uozg9EcNY@@GNMM0PK%0=l%;c^NN2MHnB~l;K{}$3u z=@b|fmChr|8wmUufLxOuF-br#hT^8A07xJW@*e@9i>!Iuek^Z4wjSQHpM?9&%$6-@ z7v##(S3W=g>G_TEt)qRp!2;F3<7r zBflES+j}>uULy&imY{7u;{h0+16QDC8^yK(IJ)TXhWR;gB)Z>?JKU%ah7;~%h9aYc zytH0Srul3_cuN`v1t`Jg834N^j^kfr&L? + .pallet-list-page { font-family: Helvetica Neue, Arial, sans-serif; } + .pallet-list-page h2 { color: #2F5496; margin-bottom: 16px; font-size: 20px; } + .pallet-search-box { margin-bottom: 16px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; } + .pallet-search-box input, .pallet-search-box select { + padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 13px; + } + .pallet-search-box button { + padding: 6px 14px; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; + font-size: 13px; background: white; + } + .pallet-search-box button.btn-primary { background: #2F5496; color: white; border-color: #2F5496; } + .pallet-search-box button.btn-success { background: #548235; color: white; border-color: #548235; } + .pallet-table-container { padding: 0; overflow-x: auto; background: white; border-radius: 4px; } + .pallet-table { width: 100%; border-collapse: collapse; font-size: 13px; } + .pallet-table th { + background: #2F5496; color: white; padding: 8px 10px; text-align: left; + cursor: pointer; white-space: nowrap; font-weight: 500; + } + .pallet-table td { padding: 5px 10px; border-bottom: 1px solid #eee; } + .pallet-table tr:hover { background: #f5f5f5; } + .pallet-table tr.new-row { background: #FFF9E6 !important; } + .pallet-table a { color: #2F5496; text-decoration: none; font-weight: 600; } + .status-received { color: #2196F3; font-weight: 600; } + .status-sorting { color: #FF9800; font-weight: 600; } + .status-processing { color: #9C27B0; font-weight: 600; } + .status-complete { color: #4CAF50; font-weight: 600; } + .status-shipped { color: #607D8B; font-weight: 600; } + .pallet-pagination { margin-top: 12px; display: flex; gap: 5px; align-items: center; } + .pallet-pagination button { + padding: 5px 12px; border: 1px solid #ddd; background: white; cursor: pointer; + border-radius: 4px; font-size: 13px; color: #2F5496; + } + .pallet-pagination button.active { background: #2F5496; color: white; border-color: #2F5496; } + .pallet-pagination button:disabled { opacity: 0.5; cursor: not-allowed; } + .pallet-count { margin-left: auto; color: #666; font-size: 13px; } + + +
+

📦 Pallet List

+ + + +
+ + + + + + + + + + + + + + + + + + + + +
Pallet # ⇅Date Reserved ⇅Rec. Date ⇅Customer # ⇅Lbs ⇅Who ⇅Items Tested ⇅QTY Sale ⇅Lbs Sale ⇅Finish Date ⇅StatusNotes
Loading...
+
+ +
+
diff --git a/westech_r2/page/pallet_list/pallet-list.js b/westech_r2/page/pallet_list/pallet-list.js new file mode 100644 index 0000000..0c3f9c1 --- /dev/null +++ b/westech_r2/page/pallet_list/pallet-list.js @@ -0,0 +1,128 @@ +frappe.pages["pallet-list"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: __("Pallet List"), + single_column: true + }); + + var content = frappe.render_template("pallet-list", {}); + $(page.body).append(content); + + var currentPage = 1; + var pageSize = 100; + var currentSort = "pallet_number"; + var sortDir = "desc"; + var searchTerm = ""; + var statusFilter = ""; + + function loadPallets() { + frappe.call({ + method: "westech_r2.page.pallet-list.pallet-list.get_pallets", + args: { + page: currentPage, + page_size: pageSize, + sort_field: currentSort, + sort_dir: sortDir, + status_filter: statusFilter, + search: searchTerm + }, + callback: function(r) { + if (r.message) { + renderPallets(r.message.pallets, r.message.total); + } + } + }); + } + + function renderPallets(pallets, total) { + var tbody = $("#pallet-tbody"); + tbody.empty(); + + if (!pallets || pallets.length === 0) { + tbody.append('No pallets found'); + return; + } + + pallets.forEach(function(p) { + var statusClass = "status-" + (p.status || "").toLowerCase().replace(/\s+/g, "-"); + var link = "/app/pallet/" + encodeURIComponent(p.name); + var pn = (p.pallet_number || "").replace(//g, ">"); + + var row = '' + + '' + pn + '' + + '' + fmtDate(p.date_reserved) + '' + + '' + fmtDate(p.received_date) + '' + + '' + (p.customer_number || "") + '' + + '' + (p.company_name || "") + '' + + '' + (p.inbound_weight || "") + '' + + '' + (p.tester || "") + '' + + '' + (p.description || "") + '' + + '' + (p.qty_to_sales || "") + '' + + '' + (p.weight_to_sales || "") + '' + + '' + fmtDate(p.finish_date) + '' + + '' + (p.status || "") + '' + + '' + (p.notes || "").substring(0, 50) + '' + + ''; + tbody.append(row); + }); + + renderPagination(total); + } + + function renderPagination(total) { + var totalPages = Math.ceil(total / pageSize); + var pagination = $("#pallet-pagination"); + pagination.empty(); + + if (totalPages <= 1) return; + + var prevBtn = $('').attr("disabled", currentPage === 1) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage > 1) { currentPage--; loadPallets(); } + }); + pagination.append(prevBtn); + + var startPage = Math.max(1, currentPage - 2); + var endPage = Math.min(totalPages, startPage + 4); + + for (var i = startPage; i <= endPage; i++) { + var btn = $('') + .css({padding: "5px 12px", border: "1px solid #ddd", background: i === currentPage ? "#3cc062" : "white", + color: i === currentPage ? "white" : "#333", cursor: "pointer", marginRight: "5px"}) + .on("click", function(page) { + return function() { currentPage = page; loadPallets(); }; + }(i)); + pagination.append(btn); + } + + var nextBtn = $('').attr("disabled", currentPage === totalPages) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage < totalPages) { currentPage++; loadPallets(); } + }); + pagination.append(nextBtn); + } + + function fmtDate(v) { + if (!v) return ""; + var s = String(v); + if (s.indexOf("T") > -1) s = s.split("T")[0]; + if (s.indexOf(" ") > -1) s = s.split(" ")[0]; + return s; + } + + $("#pallet-search").on("input", function() { + searchTerm = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + $("#status-filter").on("change", function() { + statusFilter = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + loadPallets(); +}; diff --git a/westech_r2/page/pallet_list/pallet-list.json b/westech_r2/page/pallet_list/pallet-list.json new file mode 100644 index 0000000..d7304c4 --- /dev/null +++ b/westech_r2/page/pallet_list/pallet-list.json @@ -0,0 +1,19 @@ +{ + content: null, + creation: 2026-05-19 13:00:00.000000, + docstatus: 0, + doctype: Page, + idx: 0, + modified: 2026-05-19 13:00:00.000000, + modified_by: Administrator, + module: Westech R2, + name: pallet-list, + owner: Administrator, + page_name: pallet-list, + roles: [], + script: null, + standard: Yes, + style: null, + system_page: 0, + title: Pallet List +} diff --git a/westech_r2/page/pallet_list/pallet-list.py b/westech_r2/page/pallet_list/pallet-list.py new file mode 100644 index 0000000..0a0e433 --- /dev/null +++ b/westech_r2/page/pallet_list/pallet-list.py @@ -0,0 +1,64 @@ +import frappe + +@frappe.whitelist() +def get_pallets(page=1, page_size=100, sort_field="pallet_number", sort_dir="desc", status_filter="", search=""): + page = int(page) + page_size = int(page_size) + offset = (page - 1) * page_size + + conditions = [ + "pallet_number IS NOT NULL", + "pallet_number != ''", + "date_reserved IS NOT NULL", + "customer_number IS NOT NULL", + "customer_number != ''" + ] + + junk = ["", "0", "0000", "N/A", "TBD", "null", "999990", "999995"] + junk_list = "', '".join(junk) + conditions.append("pallet_number NOT IN ('" + junk_list + "')") + conditions.append("pallet_number NOT LIKE '999%'") + conditions.append("pallet_number REGEXP '^[0-9]'") + + if status_filter: + conditions.append("status = '" + frappe.db.escape(status_filter) + "'") + if search: + conditions.append("pallet_number LIKE '%" + frappe.db.escape(search) + "%'") + + where_clause = " AND ".join(conditions) + + total = frappe.db.sql("SELECT COUNT(*) FROM tabPallet WHERE " + where_clause)[0][0] + + pallets = frappe.db.sql("SELECT name, pallet_number, date_reserved, received_date, customer_number, company_name, inbound_weight, tester, description, qty_to_sales, weight_to_sales, finish_date, notes, status FROM tabPallet WHERE " + where_clause + " ORDER BY CAST(pallet_number AS UNSIGNED) " + sort_dir + " LIMIT " + str(page_size) + " OFFSET " + str(offset), as_dict=True) + + empty_pallet = frappe.db.sql("SELECT name, pallet_number, date_reserved, received_date, customer_number, company_name, inbound_weight, tester, description, qty_to_sales, weight_to_sales, finish_date, notes, status FROM tabPallet WHERE date_reserved IS NULL AND (customer_number IS NULL OR customer_number = '') AND pallet_number NOT IN ('" + junk_list + "') AND pallet_number NOT LIKE '999%' AND pallet_number REGEXP '^[0-9]' ORDER BY CAST(pallet_number AS UNSIGNED) DESC LIMIT 1", as_dict=True) + + result = [] + if empty_pallet: + empty_pallet[0]["_is_new"] = True + result.append(empty_pallet[0]) + result.extend(pallets) + + return {"pallets": result, "total": total, "page": page, "page_size": page_size} + +@frappe.whitelist() +def update_pallet(docname, field, value): + pallet = frappe.get_doc("Pallet", docname) + pallet.set(field, value) + pallet.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Updated " + field} + +@frappe.whitelist() +def create_pallet(data): + data = frappe.parse_json(data) + pallet = frappe.new_doc("Pallet") + pallet.pallet_number = data.get("pallet_number") + pallet.status = data.get("status", "Received") + pallet.date_reserved = data.get("date_reserved") + for field, value in data.items(): + if field not in ["pallet_number", "status", "date_reserved"] and value: + pallet.set(field, value) + pallet.insert(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "name": pallet.name} diff --git a/westech_r2/page/pallet_list/pallet_list.html b/westech_r2/page/pallet_list/pallet_list.html new file mode 100644 index 0000000..c3ac405 --- /dev/null +++ b/westech_r2/page/pallet_list/pallet_list.html @@ -0,0 +1,82 @@ + + +
+

📦 Pallet List

+ + + +
+ + + + + + + + + + + + + + + + + + + + +
Pallet # ⇅Date Reserved ⇅Rec. Date ⇅Customer # ⇅Lbs ⇅Who ⇅Items Tested ⇅QTY Sale ⇅Lbs Sale ⇅Finish Date ⇅StatusNotes
Loading...
+
+ +
+
diff --git a/westech_r2/page/pallet_list/pallet_list.js b/westech_r2/page/pallet_list/pallet_list.js new file mode 100644 index 0000000..0c3f9c1 --- /dev/null +++ b/westech_r2/page/pallet_list/pallet_list.js @@ -0,0 +1,128 @@ +frappe.pages["pallet-list"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: __("Pallet List"), + single_column: true + }); + + var content = frappe.render_template("pallet-list", {}); + $(page.body).append(content); + + var currentPage = 1; + var pageSize = 100; + var currentSort = "pallet_number"; + var sortDir = "desc"; + var searchTerm = ""; + var statusFilter = ""; + + function loadPallets() { + frappe.call({ + method: "westech_r2.page.pallet-list.pallet-list.get_pallets", + args: { + page: currentPage, + page_size: pageSize, + sort_field: currentSort, + sort_dir: sortDir, + status_filter: statusFilter, + search: searchTerm + }, + callback: function(r) { + if (r.message) { + renderPallets(r.message.pallets, r.message.total); + } + } + }); + } + + function renderPallets(pallets, total) { + var tbody = $("#pallet-tbody"); + tbody.empty(); + + if (!pallets || pallets.length === 0) { + tbody.append('No pallets found'); + return; + } + + pallets.forEach(function(p) { + var statusClass = "status-" + (p.status || "").toLowerCase().replace(/\s+/g, "-"); + var link = "/app/pallet/" + encodeURIComponent(p.name); + var pn = (p.pallet_number || "").replace(//g, ">"); + + var row = '' + + '' + pn + '' + + '' + fmtDate(p.date_reserved) + '' + + '' + fmtDate(p.received_date) + '' + + '' + (p.customer_number || "") + '' + + '' + (p.company_name || "") + '' + + '' + (p.inbound_weight || "") + '' + + '' + (p.tester || "") + '' + + '' + (p.description || "") + '' + + '' + (p.qty_to_sales || "") + '' + + '' + (p.weight_to_sales || "") + '' + + '' + fmtDate(p.finish_date) + '' + + '' + (p.status || "") + '' + + '' + (p.notes || "").substring(0, 50) + '' + + ''; + tbody.append(row); + }); + + renderPagination(total); + } + + function renderPagination(total) { + var totalPages = Math.ceil(total / pageSize); + var pagination = $("#pallet-pagination"); + pagination.empty(); + + if (totalPages <= 1) return; + + var prevBtn = $('').attr("disabled", currentPage === 1) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage > 1) { currentPage--; loadPallets(); } + }); + pagination.append(prevBtn); + + var startPage = Math.max(1, currentPage - 2); + var endPage = Math.min(totalPages, startPage + 4); + + for (var i = startPage; i <= endPage; i++) { + var btn = $('') + .css({padding: "5px 12px", border: "1px solid #ddd", background: i === currentPage ? "#3cc062" : "white", + color: i === currentPage ? "white" : "#333", cursor: "pointer", marginRight: "5px"}) + .on("click", function(page) { + return function() { currentPage = page; loadPallets(); }; + }(i)); + pagination.append(btn); + } + + var nextBtn = $('').attr("disabled", currentPage === totalPages) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage < totalPages) { currentPage++; loadPallets(); } + }); + pagination.append(nextBtn); + } + + function fmtDate(v) { + if (!v) return ""; + var s = String(v); + if (s.indexOf("T") > -1) s = s.split("T")[0]; + if (s.indexOf(" ") > -1) s = s.split(" ")[0]; + return s; + } + + $("#pallet-search").on("input", function() { + searchTerm = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + $("#status-filter").on("change", function() { + statusFilter = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + loadPallets(); +}; diff --git a/westech_r2/page/pallet_list/pallet_list.json b/westech_r2/page/pallet_list/pallet_list.json new file mode 100644 index 0000000..d7304c4 --- /dev/null +++ b/westech_r2/page/pallet_list/pallet_list.json @@ -0,0 +1,19 @@ +{ + content: null, + creation: 2026-05-19 13:00:00.000000, + docstatus: 0, + doctype: Page, + idx: 0, + modified: 2026-05-19 13:00:00.000000, + modified_by: Administrator, + module: Westech R2, + name: pallet-list, + owner: Administrator, + page_name: pallet-list, + roles: [], + script: null, + standard: Yes, + style: null, + system_page: 0, + title: Pallet List +} diff --git a/westech_r2/page/pallet_list/pallet_list.py b/westech_r2/page/pallet_list/pallet_list.py new file mode 100644 index 0000000..0a0e433 --- /dev/null +++ b/westech_r2/page/pallet_list/pallet_list.py @@ -0,0 +1,64 @@ +import frappe + +@frappe.whitelist() +def get_pallets(page=1, page_size=100, sort_field="pallet_number", sort_dir="desc", status_filter="", search=""): + page = int(page) + page_size = int(page_size) + offset = (page - 1) * page_size + + conditions = [ + "pallet_number IS NOT NULL", + "pallet_number != ''", + "date_reserved IS NOT NULL", + "customer_number IS NOT NULL", + "customer_number != ''" + ] + + junk = ["", "0", "0000", "N/A", "TBD", "null", "999990", "999995"] + junk_list = "', '".join(junk) + conditions.append("pallet_number NOT IN ('" + junk_list + "')") + conditions.append("pallet_number NOT LIKE '999%'") + conditions.append("pallet_number REGEXP '^[0-9]'") + + if status_filter: + conditions.append("status = '" + frappe.db.escape(status_filter) + "'") + if search: + conditions.append("pallet_number LIKE '%" + frappe.db.escape(search) + "%'") + + where_clause = " AND ".join(conditions) + + total = frappe.db.sql("SELECT COUNT(*) FROM tabPallet WHERE " + where_clause)[0][0] + + pallets = frappe.db.sql("SELECT name, pallet_number, date_reserved, received_date, customer_number, company_name, inbound_weight, tester, description, qty_to_sales, weight_to_sales, finish_date, notes, status FROM tabPallet WHERE " + where_clause + " ORDER BY CAST(pallet_number AS UNSIGNED) " + sort_dir + " LIMIT " + str(page_size) + " OFFSET " + str(offset), as_dict=True) + + empty_pallet = frappe.db.sql("SELECT name, pallet_number, date_reserved, received_date, customer_number, company_name, inbound_weight, tester, description, qty_to_sales, weight_to_sales, finish_date, notes, status FROM tabPallet WHERE date_reserved IS NULL AND (customer_number IS NULL OR customer_number = '') AND pallet_number NOT IN ('" + junk_list + "') AND pallet_number NOT LIKE '999%' AND pallet_number REGEXP '^[0-9]' ORDER BY CAST(pallet_number AS UNSIGNED) DESC LIMIT 1", as_dict=True) + + result = [] + if empty_pallet: + empty_pallet[0]["_is_new"] = True + result.append(empty_pallet[0]) + result.extend(pallets) + + return {"pallets": result, "total": total, "page": page, "page_size": page_size} + +@frappe.whitelist() +def update_pallet(docname, field, value): + pallet = frappe.get_doc("Pallet", docname) + pallet.set(field, value) + pallet.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Updated " + field} + +@frappe.whitelist() +def create_pallet(data): + data = frappe.parse_json(data) + pallet = frappe.new_doc("Pallet") + pallet.pallet_number = data.get("pallet_number") + pallet.status = data.get("status", "Received") + pallet.date_reserved = data.get("date_reserved") + for field, value in data.items(): + if field not in ["pallet_number", "status", "date_reserved"] and value: + pallet.set(field, value) + pallet.insert(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "name": pallet.name} diff --git a/westech_r2/page/route-planner/route-planner.html b/westech_r2/page/route-planner/route-planner.html new file mode 100644 index 0000000..0116139 --- /dev/null +++ b/westech_r2/page/route-planner/route-planner.html @@ -0,0 +1,4 @@ +
+

Route Planner

+

Optimize pickup routes for scheduled pickups.

+
diff --git a/westech_r2/page/route-planner/route-planner.js b/westech_r2/page/route-planner/route-planner.js new file mode 100644 index 0000000..9d8ff74 --- /dev/null +++ b/westech_r2/page/route-planner/route-planner.js @@ -0,0 +1,38 @@ +frappe.pages["route-planner"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Route Planner", + single_column: true + }); + + frappe.call({ + method: "westech_r2.api.optimize_routes.get_scheduled_pickups", + callback: function(r) { + if (r.message) { + renderRoutePlanner(page, r.message); + } + } + }); + + function renderRoutePlanner(page, data) { + var h = "
"; + h += "

Route Planner

"; + h += "

Schedule and optimize pickup routes.

"; + h += "
"; + h += ""; + h += "
"; + h += "
"; + $(page.body).html(h); + + $("#optimize-btn").on("click", function() { + frappe.call({ + method: "westech_r2.api.optimize_routes.optimize_routes", + callback: function(r) { + if (r.message) { + frappe.show_alert({message: "Routes optimized", indicator: "green"}); + } + } + }); + }); + } +}; diff --git a/westech_r2/page/route-planner/route-planner.json b/westech_r2/page/route-planner/route-planner.json new file mode 100644 index 0000000..7e8b89e --- /dev/null +++ b/westech_r2/page/route-planner/route-planner.json @@ -0,0 +1,9 @@ +{ + "doctype": "Page", + "name": "route-planner", + "page_name": "route-planner", + "title": "Route Planner", + "module": "Westech R2", + "standard": "Yes", + "roles": [{"role": "All"}] +} diff --git a/westech_r2/page/route_planner/route_planner.html b/westech_r2/page/route_planner/route_planner.html new file mode 100644 index 0000000..0116139 --- /dev/null +++ b/westech_r2/page/route_planner/route_planner.html @@ -0,0 +1,4 @@ +
+

Route Planner

+

Optimize pickup routes for scheduled pickups.

+
diff --git a/westech_r2/page/route_planner/route_planner.js b/westech_r2/page/route_planner/route_planner.js new file mode 100644 index 0000000..9d8ff74 --- /dev/null +++ b/westech_r2/page/route_planner/route_planner.js @@ -0,0 +1,38 @@ +frappe.pages["route-planner"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Route Planner", + single_column: true + }); + + frappe.call({ + method: "westech_r2.api.optimize_routes.get_scheduled_pickups", + callback: function(r) { + if (r.message) { + renderRoutePlanner(page, r.message); + } + } + }); + + function renderRoutePlanner(page, data) { + var h = "
"; + h += "

Route Planner

"; + h += "

Schedule and optimize pickup routes.

"; + h += "
"; + h += ""; + h += "
"; + h += "
"; + $(page.body).html(h); + + $("#optimize-btn").on("click", function() { + frappe.call({ + method: "westech_r2.api.optimize_routes.optimize_routes", + callback: function(r) { + if (r.message) { + frappe.show_alert({message: "Routes optimized", indicator: "green"}); + } + } + }); + }); + } +}; diff --git a/westech_r2/page/route_planner/route_planner.json b/westech_r2/page/route_planner/route_planner.json new file mode 100644 index 0000000..7e8b89e --- /dev/null +++ b/westech_r2/page/route_planner/route_planner.json @@ -0,0 +1,9 @@ +{ + "doctype": "Page", + "name": "route-planner", + "page_name": "route-planner", + "title": "Route Planner", + "module": "Westech R2", + "standard": "Yes", + "roles": [{"role": "All"}] +} diff --git a/westech_r2/westech_r2/page/__init__.py b/westech_r2/westech_r2/page/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/westech_r2/page/load-detail/load-detail.json b/westech_r2/westech_r2/page/load-detail/load-detail.json new file mode 100644 index 0000000..fdf173c --- /dev/null +++ b/westech_r2/westech_r2/page/load-detail/load-detail.json @@ -0,0 +1 @@ +{"content": "
\n\n\n
\n

Load:

\n
In Date: | Customer: | Devices: | Weight: lbs
\n
\n\n
\n Receiving\n HDR / Disassembly\n Test\n R2 Downstream\n Destruction\n
\n\n\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Material TypeReceivingHDR / DisassemblyTestR2Destruction
CountStatusSend ToRecv'dHDD OutSend ToSanitizedStatusSend ToSentPhysHDD NeedHDD PhysHDD Logic
\n\n\n
\n", "title": "Load Detail", "route": "load-detail"} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/load-detail/load_detail.json b/westech_r2/westech_r2/page/load-detail/load_detail.json new file mode 100644 index 0000000..fdf173c --- /dev/null +++ b/westech_r2/westech_r2/page/load-detail/load_detail.json @@ -0,0 +1 @@ +{"content": "
\n\n\n
\n

Load:

\n
In Date: | Customer: | Devices: | Weight: lbs
\n
\n\n
\n Receiving\n HDR / Disassembly\n Test\n R2 Downstream\n Destruction\n
\n\n\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Material TypeReceivingHDR / DisassemblyTestR2Destruction
CountStatusSend ToRecv'dHDD OutSend ToSanitizedStatusSend ToSentPhysHDD NeedHDD PhysHDD Logic
\n\n\n
\n", "title": "Load Detail", "route": "load-detail"} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/load-update/__init__.py b/westech_r2/westech_r2/page/load-update/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/westech_r2/page/load-update/load_update.js b/westech_r2/westech_r2/page/load-update/load_update.js new file mode 100644 index 0000000..bd7fac9 --- /dev/null +++ b/westech_r2/westech_r2/page/load-update/load_update.js @@ -0,0 +1,7 @@ +frappe.pages['load-update'].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: 'Load Update', + single_column: true + }); +} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/load-update/load_update.json b/westech_r2/westech_r2/page/load-update/load_update.json new file mode 100644 index 0000000..59ee53b --- /dev/null +++ b/westech_r2/westech_r2/page/load-update/load_update.json @@ -0,0 +1,23 @@ +{ + "content": null, + "creation": "2026-05-19 19:43:48.962424", + "docstatus": 0, + "doctype": "Page", + "idx": 0, + "modified": "2026-05-19 19:43:48.962424", + "modified_by": "Administrator", + "module": "Westech R2", + "name": "load-update", + "owner": "Administrator", + "page_name": "load-update", + "roles": [ + { + "role": "All" + } + ], + "script": null, + "standard": "Yes", + "style": null, + "system_page": 0, + "title": "Load Update" +} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/load_detail/__init__.py b/westech_r2/westech_r2/page/load_detail/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/westech_r2/page/load_detail/load-detail.js b/westech_r2/westech_r2/page/load_detail/load-detail.js new file mode 100644 index 0000000..b13cdca --- /dev/null +++ b/westech_r2/westech_r2/page/load_detail/load-detail.js @@ -0,0 +1,65 @@ +frappe.pages["load-detail"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Detail", + single_column: true + }); + + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { showLoad(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + + function showLoad(page, load) { + var h = "
"; + h += "
"; + h += "

Load: " + load.name + "

"; + h += "
In Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "
"; + h += "
Devices: " + (load.total_devices || 0) + " | Weight: " + (load.total_weight || 0) + " lbs
"; + h += "
"; + h += " "; + h += "Open Form View "; + h += "Edit Load"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item) { + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRcv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "" + (item.total_count || 0) + "" + (item.initial_data_status || "") + "" + (item.send_to || "") + "" + (item.devices_received || 0) + "" + (item.hdd_removed || 0) + "" + (item.disassembly_send_to || "") + "" + (item.units_sanitized_software || 0) + "" + (item.test_data_status || "") + "" + (item.test_send_to || "") + "" + (item.r2_units_sent || 0) + "" + (item.units_physical_destruction || 0) + "" + (item.hdd_needs_sanitize || 0) + "" + (item.hdd_physical_destruction || 0) + "" + (item.hdd_logical_sanitization || 0) + "
"; + $(page.body).html(h); + } +}; diff --git a/westech_r2/westech_r2/page/load_detail/load-detail.json b/westech_r2/westech_r2/page/load_detail/load-detail.json new file mode 100644 index 0000000..fdf173c --- /dev/null +++ b/westech_r2/westech_r2/page/load_detail/load-detail.json @@ -0,0 +1 @@ +{"content": "
\n\n\n
\n

Load:

\n
In Date: | Customer: | Devices: | Weight: lbs
\n
\n\n
\n Receiving\n HDR / Disassembly\n Test\n R2 Downstream\n Destruction\n
\n\n\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Material TypeReceivingHDR / DisassemblyTestR2Destruction
CountStatusSend ToRecv'dHDD OutSend ToSanitizedStatusSend ToSentPhysHDD NeedHDD PhysHDD Logic
\n\n\n
\n", "title": "Load Detail", "route": "load-detail"} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/load_detail/load_detail.html b/westech_r2/westech_r2/page/load_detail/load_detail.html new file mode 100644 index 0000000..ec9f8f8 --- /dev/null +++ b/westech_r2/westech_r2/page/load_detail/load_detail.html @@ -0,0 +1,53 @@ +
+ + +
+

Load:

+
In Date: | Customer: | Devices: | Weight: lbs
+
+ +
+ Receiving + HDR / Disassembly + Test + R2 Downstream + Destruction +
+ + + + + + + + + + + + + + + + + + + + + + + +
Material TypeReceivingHDR / DisassemblyTestR2Destruction
CountStatusSend ToRecv'dHDD OutSend ToSanitizedStatusSend ToSentPhysHDD NeedHDD PhysHDD Logic
+
\ No newline at end of file diff --git a/westech_r2/westech_r2/page/load_detail/load_detail.js b/westech_r2/westech_r2/page/load_detail/load_detail.js new file mode 100644 index 0000000..b13cdca --- /dev/null +++ b/westech_r2/westech_r2/page/load_detail/load_detail.js @@ -0,0 +1,65 @@ +frappe.pages["load-detail"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Detail", + single_column: true + }); + + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { showLoad(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + + function showLoad(page, load) { + var h = "
"; + h += "
"; + h += "

Load: " + load.name + "

"; + h += "
In Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "
"; + h += "
Devices: " + (load.total_devices || 0) + " | Weight: " + (load.total_weight || 0) + " lbs
"; + h += "
"; + h += " "; + h += "Open Form View "; + h += "Edit Load"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item) { + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRcv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "" + (item.total_count || 0) + "" + (item.initial_data_status || "") + "" + (item.send_to || "") + "" + (item.devices_received || 0) + "" + (item.hdd_removed || 0) + "" + (item.disassembly_send_to || "") + "" + (item.units_sanitized_software || 0) + "" + (item.test_data_status || "") + "" + (item.test_send_to || "") + "" + (item.r2_units_sent || 0) + "" + (item.units_physical_destruction || 0) + "" + (item.hdd_needs_sanitize || 0) + "" + (item.hdd_physical_destruction || 0) + "" + (item.hdd_logical_sanitization || 0) + "
"; + $(page.body).html(h); + } +}; diff --git a/westech_r2/westech_r2/page/load_detail/load_detail.json b/westech_r2/westech_r2/page/load_detail/load_detail.json new file mode 100644 index 0000000..b907099 --- /dev/null +++ b/westech_r2/westech_r2/page/load_detail/load_detail.json @@ -0,0 +1,23 @@ +{ + "content": null, + "creation": "2026-05-19 19:43:48.923372", + "docstatus": 0, + "doctype": "Page", + "idx": 0, + "modified": "2026-05-19 19:43:48.923372", + "modified_by": "Administrator", + "module": "Westech R2", + "name": "load-detail", + "owner": "Administrator", + "page_name": "load-detail", + "roles": [ + { + "role": "All" + } + ], + "script": null, + "standard": "Yes", + "style": null, + "system_page": 0, + "title": "Load Detail" +} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/load_update/__init__.py b/westech_r2/westech_r2/page/load_update/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/westech_r2/page/load_update/load-update.js b/westech_r2/westech_r2/page/load_update/load-update.js new file mode 100644 index 0000000..5c03738 --- /dev/null +++ b/westech_r2/westech_r2/page/load_update/load-update.js @@ -0,0 +1,109 @@ +frappe.pages["load-update"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Update", + single_column: true + }); + + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + function loadLoad() { + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { renderForm(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + } + + function renderForm(page, load) { + var h = "
"; + h += "

Update Load: " + load.name + "

"; + h += "

Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "

"; + h += "
"; + h += " "; + h += " "; + h += "Open Form View"; + h += "
"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item, idx) { + var prefix = "item_" + idx + "_"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRecv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "
"; + $(page.body).html(h); + + $("#lu-save").on("click", function() { + var items = []; + load.material_items.forEach(function(item, idx) { + var prefix = "#item_" + idx + "_"; + items.push({ + name: item.name, + total_count: parseInt($(prefix + "total_count").val()) || 0, + initial_data_status: $(prefix + "initial_data_status").val(), + send_to: $(prefix + "send_to").val(), + devices_received: parseInt($(prefix + "devices_received").val()) || 0, + hdd_removed: parseInt($(prefix + "hdd_removed").val()) || 0, + disassembly_send_to: $(prefix + "disassembly_send_to").val(), + units_sanitized_software: parseInt($(prefix + "units_sanitized_software").val()) || 0, + test_data_status: $(prefix + "test_data_status").val(), + test_send_to: $(prefix + "test_send_to").val(), + r2_units_sent: parseInt($(prefix + "r2_units_sent").val()) || 0, + units_physical_destruction: parseInt($(prefix + "units_physical_destruction").val()) || 0, + hdd_needs_sanitize: parseInt($(prefix + "hdd_needs_sanitize").val()) || 0, + hdd_physical_destruction: parseInt($(prefix + "hdd_physical_destruction").val()) || 0, + hdd_logical_sanitization: parseInt($(prefix + "hdd_logical_sanitization").val()) || 0 + }); + }); + frappe.call({ + method: "westech_r2.page.load-update.load-update.save_load_items", + args: { load_name: loadName, items: JSON.stringify(items) }, + callback: function(r) { + if (r.message && r.message.status === "ok") { + frappe.show_alert({message: "Saved", indicator: "green"}); + loadLoad(); + } else { + frappe.show_alert({message: "Save failed", indicator: "red"}); + } + } + }); + }); + + $("#lu-print").on("click", function() { + window.print(); + }); + } + + loadLoad(); +}; diff --git a/westech_r2/westech_r2/page/load_update/load_update.html b/westech_r2/westech_r2/page/load_update/load_update.html new file mode 100644 index 0000000..6e7e05e --- /dev/null +++ b/westech_r2/westech_r2/page/load_update/load_update.html @@ -0,0 +1,4 @@ +
+

Load Update

+

Use the form below to update load material items.

+
diff --git a/westech_r2/westech_r2/page/load_update/load_update.js b/westech_r2/westech_r2/page/load_update/load_update.js new file mode 100644 index 0000000..5c03738 --- /dev/null +++ b/westech_r2/westech_r2/page/load_update/load_update.js @@ -0,0 +1,109 @@ +frappe.pages["load-update"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Load Update", + single_column: true + }); + + var loadName = frappe.utils.get_url_arg("load"); + if (!loadName) { + $(page.body).html("

No load specified

Use ?load=MMDDYYYY-XXXX

"); + return; + } + + function loadLoad() { + frappe.call({ + method: "frappe.client.get", + args: { doctype: "Load", name: loadName }, + callback: function(r) { + if (r.message) { renderForm(page, r.message); } + else { $(page.body).html("

Load not found

"); } + } + }); + } + + function renderForm(page, load) { + var h = "
"; + h += "

Update Load: " + load.name + "

"; + h += "

Date: " + (load.incoming_date || "N/A") + " | Customer: " + (load.customer_name || load.customer_number || "N/A") + "

"; + h += "
"; + h += " "; + h += " "; + h += "Open Form View"; + h += "
"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + + if (load.material_items && load.material_items.length > 0) { + load.material_items.forEach(function(item, idx) { + var prefix = "item_" + idx + "_"; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + h += ""; + }); + } + h += "
Material TypeCountRecv StatusSend ToRecv'dHDD OutDis Send ToSanitizedTest StatusTest SendR2 SentPhysHDD NeedHDD PhysHDD Logic
" + (item.material_type || "") + "
"; + $(page.body).html(h); + + $("#lu-save").on("click", function() { + var items = []; + load.material_items.forEach(function(item, idx) { + var prefix = "#item_" + idx + "_"; + items.push({ + name: item.name, + total_count: parseInt($(prefix + "total_count").val()) || 0, + initial_data_status: $(prefix + "initial_data_status").val(), + send_to: $(prefix + "send_to").val(), + devices_received: parseInt($(prefix + "devices_received").val()) || 0, + hdd_removed: parseInt($(prefix + "hdd_removed").val()) || 0, + disassembly_send_to: $(prefix + "disassembly_send_to").val(), + units_sanitized_software: parseInt($(prefix + "units_sanitized_software").val()) || 0, + test_data_status: $(prefix + "test_data_status").val(), + test_send_to: $(prefix + "test_send_to").val(), + r2_units_sent: parseInt($(prefix + "r2_units_sent").val()) || 0, + units_physical_destruction: parseInt($(prefix + "units_physical_destruction").val()) || 0, + hdd_needs_sanitize: parseInt($(prefix + "hdd_needs_sanitize").val()) || 0, + hdd_physical_destruction: parseInt($(prefix + "hdd_physical_destruction").val()) || 0, + hdd_logical_sanitization: parseInt($(prefix + "hdd_logical_sanitization").val()) || 0 + }); + }); + frappe.call({ + method: "westech_r2.page.load-update.load-update.save_load_items", + args: { load_name: loadName, items: JSON.stringify(items) }, + callback: function(r) { + if (r.message && r.message.status === "ok") { + frappe.show_alert({message: "Saved", indicator: "green"}); + loadLoad(); + } else { + frappe.show_alert({message: "Save failed", indicator: "red"}); + } + } + }); + }); + + $("#lu-print").on("click", function() { + window.print(); + }); + } + + loadLoad(); +}; diff --git a/westech_r2/westech_r2/page/load_update/load_update.json b/westech_r2/westech_r2/page/load_update/load_update.json new file mode 100644 index 0000000..36a0249 --- /dev/null +++ b/westech_r2/westech_r2/page/load_update/load_update.json @@ -0,0 +1,23 @@ +{ + "content": null, + "creation": "2026-05-19 20:47:42.992119", + "docstatus": 0, + "doctype": "Page", + "idx": 0, + "modified": "2026-05-19 20:47:42.992119", + "modified_by": "Administrator", + "module": "Westech R2", + "name": "load-update", + "owner": "Administrator", + "page_name": "load-update", + "roles": [ + { + "role": "All" + } + ], + "script": null, + "standard": "Yes", + "style": null, + "system_page": 0, + "title": "Load Update" +} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/load_update/load_update.py b/westech_r2/westech_r2/page/load_update/load_update.py new file mode 100644 index 0000000..4afaf5e --- /dev/null +++ b/westech_r2/westech_r2/page/load_update/load_update.py @@ -0,0 +1,17 @@ +import frappe +import json + +@frappe.whitelist() +def save_load_items(load_name, items): + items = json.loads(items) + load_doc = frappe.get_doc("Load", load_name) + for item_data in items: + for row in load_doc.material_items: + if row.name == item_data["name"]: + for field, value in item_data.items(): + if field != "name": + row.set(field, value) + break + load_doc.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Saved " + str(len(items)) + " items"} diff --git a/westech_r2/westech_r2/page/pallet-list/__init__.py b/westech_r2/westech_r2/page/pallet-list/__init__.py new file mode 100644 index 0000000..eb0d74d --- /dev/null +++ b/westech_r2/westech_r2/page/pallet-list/__init__.py @@ -0,0 +1 @@ +# Pallet List page for Westech R2 diff --git a/westech_r2/westech_r2/page/pallet-list/pallet-list.html b/westech_r2/westech_r2/page/pallet-list/pallet-list.html new file mode 100644 index 0000000..c3ac405 --- /dev/null +++ b/westech_r2/westech_r2/page/pallet-list/pallet-list.html @@ -0,0 +1,82 @@ + + +
+

📦 Pallet List

+ + + +
+ + + + + + + + + + + + + + + + + + + + +
Pallet # ⇅Date Reserved ⇅Rec. Date ⇅Customer # ⇅Lbs ⇅Who ⇅Items Tested ⇅QTY Sale ⇅Lbs Sale ⇅Finish Date ⇅StatusNotes
Loading...
+
+ +
+
diff --git a/westech_r2/westech_r2/page/pallet-list/pallet-list.js b/westech_r2/westech_r2/page/pallet-list/pallet-list.js new file mode 100644 index 0000000..0c3f9c1 --- /dev/null +++ b/westech_r2/westech_r2/page/pallet-list/pallet-list.js @@ -0,0 +1,128 @@ +frappe.pages["pallet-list"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: __("Pallet List"), + single_column: true + }); + + var content = frappe.render_template("pallet-list", {}); + $(page.body).append(content); + + var currentPage = 1; + var pageSize = 100; + var currentSort = "pallet_number"; + var sortDir = "desc"; + var searchTerm = ""; + var statusFilter = ""; + + function loadPallets() { + frappe.call({ + method: "westech_r2.page.pallet-list.pallet-list.get_pallets", + args: { + page: currentPage, + page_size: pageSize, + sort_field: currentSort, + sort_dir: sortDir, + status_filter: statusFilter, + search: searchTerm + }, + callback: function(r) { + if (r.message) { + renderPallets(r.message.pallets, r.message.total); + } + } + }); + } + + function renderPallets(pallets, total) { + var tbody = $("#pallet-tbody"); + tbody.empty(); + + if (!pallets || pallets.length === 0) { + tbody.append('No pallets found'); + return; + } + + pallets.forEach(function(p) { + var statusClass = "status-" + (p.status || "").toLowerCase().replace(/\s+/g, "-"); + var link = "/app/pallet/" + encodeURIComponent(p.name); + var pn = (p.pallet_number || "").replace(//g, ">"); + + var row = '' + + '' + pn + '' + + '' + fmtDate(p.date_reserved) + '' + + '' + fmtDate(p.received_date) + '' + + '' + (p.customer_number || "") + '' + + '' + (p.company_name || "") + '' + + '' + (p.inbound_weight || "") + '' + + '' + (p.tester || "") + '' + + '' + (p.description || "") + '' + + '' + (p.qty_to_sales || "") + '' + + '' + (p.weight_to_sales || "") + '' + + '' + fmtDate(p.finish_date) + '' + + '' + (p.status || "") + '' + + '' + (p.notes || "").substring(0, 50) + '' + + ''; + tbody.append(row); + }); + + renderPagination(total); + } + + function renderPagination(total) { + var totalPages = Math.ceil(total / pageSize); + var pagination = $("#pallet-pagination"); + pagination.empty(); + + if (totalPages <= 1) return; + + var prevBtn = $('').attr("disabled", currentPage === 1) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage > 1) { currentPage--; loadPallets(); } + }); + pagination.append(prevBtn); + + var startPage = Math.max(1, currentPage - 2); + var endPage = Math.min(totalPages, startPage + 4); + + for (var i = startPage; i <= endPage; i++) { + var btn = $('') + .css({padding: "5px 12px", border: "1px solid #ddd", background: i === currentPage ? "#3cc062" : "white", + color: i === currentPage ? "white" : "#333", cursor: "pointer", marginRight: "5px"}) + .on("click", function(page) { + return function() { currentPage = page; loadPallets(); }; + }(i)); + pagination.append(btn); + } + + var nextBtn = $('').attr("disabled", currentPage === totalPages) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage < totalPages) { currentPage++; loadPallets(); } + }); + pagination.append(nextBtn); + } + + function fmtDate(v) { + if (!v) return ""; + var s = String(v); + if (s.indexOf("T") > -1) s = s.split("T")[0]; + if (s.indexOf(" ") > -1) s = s.split(" ")[0]; + return s; + } + + $("#pallet-search").on("input", function() { + searchTerm = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + $("#status-filter").on("change", function() { + statusFilter = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + loadPallets(); +}; diff --git a/westech_r2/westech_r2/page/pallet-list/pallet-list.json b/westech_r2/westech_r2/page/pallet-list/pallet-list.json new file mode 100644 index 0000000..d7304c4 --- /dev/null +++ b/westech_r2/westech_r2/page/pallet-list/pallet-list.json @@ -0,0 +1,19 @@ +{ + content: null, + creation: 2026-05-19 13:00:00.000000, + docstatus: 0, + doctype: Page, + idx: 0, + modified: 2026-05-19 13:00:00.000000, + modified_by: Administrator, + module: Westech R2, + name: pallet-list, + owner: Administrator, + page_name: pallet-list, + roles: [], + script: null, + standard: Yes, + style: null, + system_page: 0, + title: Pallet List +} diff --git a/westech_r2/westech_r2/page/pallet-list/pallet-list.py b/westech_r2/westech_r2/page/pallet-list/pallet-list.py new file mode 100644 index 0000000..0a0e433 --- /dev/null +++ b/westech_r2/westech_r2/page/pallet-list/pallet-list.py @@ -0,0 +1,64 @@ +import frappe + +@frappe.whitelist() +def get_pallets(page=1, page_size=100, sort_field="pallet_number", sort_dir="desc", status_filter="", search=""): + page = int(page) + page_size = int(page_size) + offset = (page - 1) * page_size + + conditions = [ + "pallet_number IS NOT NULL", + "pallet_number != ''", + "date_reserved IS NOT NULL", + "customer_number IS NOT NULL", + "customer_number != ''" + ] + + junk = ["", "0", "0000", "N/A", "TBD", "null", "999990", "999995"] + junk_list = "', '".join(junk) + conditions.append("pallet_number NOT IN ('" + junk_list + "')") + conditions.append("pallet_number NOT LIKE '999%'") + conditions.append("pallet_number REGEXP '^[0-9]'") + + if status_filter: + conditions.append("status = '" + frappe.db.escape(status_filter) + "'") + if search: + conditions.append("pallet_number LIKE '%" + frappe.db.escape(search) + "%'") + + where_clause = " AND ".join(conditions) + + total = frappe.db.sql("SELECT COUNT(*) FROM tabPallet WHERE " + where_clause)[0][0] + + pallets = frappe.db.sql("SELECT name, pallet_number, date_reserved, received_date, customer_number, company_name, inbound_weight, tester, description, qty_to_sales, weight_to_sales, finish_date, notes, status FROM tabPallet WHERE " + where_clause + " ORDER BY CAST(pallet_number AS UNSIGNED) " + sort_dir + " LIMIT " + str(page_size) + " OFFSET " + str(offset), as_dict=True) + + empty_pallet = frappe.db.sql("SELECT name, pallet_number, date_reserved, received_date, customer_number, company_name, inbound_weight, tester, description, qty_to_sales, weight_to_sales, finish_date, notes, status FROM tabPallet WHERE date_reserved IS NULL AND (customer_number IS NULL OR customer_number = '') AND pallet_number NOT IN ('" + junk_list + "') AND pallet_number NOT LIKE '999%' AND pallet_number REGEXP '^[0-9]' ORDER BY CAST(pallet_number AS UNSIGNED) DESC LIMIT 1", as_dict=True) + + result = [] + if empty_pallet: + empty_pallet[0]["_is_new"] = True + result.append(empty_pallet[0]) + result.extend(pallets) + + return {"pallets": result, "total": total, "page": page, "page_size": page_size} + +@frappe.whitelist() +def update_pallet(docname, field, value): + pallet = frappe.get_doc("Pallet", docname) + pallet.set(field, value) + pallet.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Updated " + field} + +@frappe.whitelist() +def create_pallet(data): + data = frappe.parse_json(data) + pallet = frappe.new_doc("Pallet") + pallet.pallet_number = data.get("pallet_number") + pallet.status = data.get("status", "Received") + pallet.date_reserved = data.get("date_reserved") + for field, value in data.items(): + if field not in ["pallet_number", "status", "date_reserved"] and value: + pallet.set(field, value) + pallet.insert(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "name": pallet.name} diff --git a/westech_r2/westech_r2/page/pallet_list/pallet_list.html b/westech_r2/westech_r2/page/pallet_list/pallet_list.html new file mode 100644 index 0000000..c3ac405 --- /dev/null +++ b/westech_r2/westech_r2/page/pallet_list/pallet_list.html @@ -0,0 +1,82 @@ + + +
+

📦 Pallet List

+ + + +
+ + + + + + + + + + + + + + + + + + + + +
Pallet # ⇅Date Reserved ⇅Rec. Date ⇅Customer # ⇅Lbs ⇅Who ⇅Items Tested ⇅QTY Sale ⇅Lbs Sale ⇅Finish Date ⇅StatusNotes
Loading...
+
+ +
+
diff --git a/westech_r2/westech_r2/page/pallet_list/pallet_list.js b/westech_r2/westech_r2/page/pallet_list/pallet_list.js new file mode 100644 index 0000000..0c3f9c1 --- /dev/null +++ b/westech_r2/westech_r2/page/pallet_list/pallet_list.js @@ -0,0 +1,128 @@ +frappe.pages["pallet-list"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: __("Pallet List"), + single_column: true + }); + + var content = frappe.render_template("pallet-list", {}); + $(page.body).append(content); + + var currentPage = 1; + var pageSize = 100; + var currentSort = "pallet_number"; + var sortDir = "desc"; + var searchTerm = ""; + var statusFilter = ""; + + function loadPallets() { + frappe.call({ + method: "westech_r2.page.pallet-list.pallet-list.get_pallets", + args: { + page: currentPage, + page_size: pageSize, + sort_field: currentSort, + sort_dir: sortDir, + status_filter: statusFilter, + search: searchTerm + }, + callback: function(r) { + if (r.message) { + renderPallets(r.message.pallets, r.message.total); + } + } + }); + } + + function renderPallets(pallets, total) { + var tbody = $("#pallet-tbody"); + tbody.empty(); + + if (!pallets || pallets.length === 0) { + tbody.append('No pallets found'); + return; + } + + pallets.forEach(function(p) { + var statusClass = "status-" + (p.status || "").toLowerCase().replace(/\s+/g, "-"); + var link = "/app/pallet/" + encodeURIComponent(p.name); + var pn = (p.pallet_number || "").replace(//g, ">"); + + var row = '' + + '' + pn + '' + + '' + fmtDate(p.date_reserved) + '' + + '' + fmtDate(p.received_date) + '' + + '' + (p.customer_number || "") + '' + + '' + (p.company_name || "") + '' + + '' + (p.inbound_weight || "") + '' + + '' + (p.tester || "") + '' + + '' + (p.description || "") + '' + + '' + (p.qty_to_sales || "") + '' + + '' + (p.weight_to_sales || "") + '' + + '' + fmtDate(p.finish_date) + '' + + '' + (p.status || "") + '' + + '' + (p.notes || "").substring(0, 50) + '' + + ''; + tbody.append(row); + }); + + renderPagination(total); + } + + function renderPagination(total) { + var totalPages = Math.ceil(total / pageSize); + var pagination = $("#pallet-pagination"); + pagination.empty(); + + if (totalPages <= 1) return; + + var prevBtn = $('').attr("disabled", currentPage === 1) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage > 1) { currentPage--; loadPallets(); } + }); + pagination.append(prevBtn); + + var startPage = Math.max(1, currentPage - 2); + var endPage = Math.min(totalPages, startPage + 4); + + for (var i = startPage; i <= endPage; i++) { + var btn = $('') + .css({padding: "5px 12px", border: "1px solid #ddd", background: i === currentPage ? "#3cc062" : "white", + color: i === currentPage ? "white" : "#333", cursor: "pointer", marginRight: "5px"}) + .on("click", function(page) { + return function() { currentPage = page; loadPallets(); }; + }(i)); + pagination.append(btn); + } + + var nextBtn = $('').attr("disabled", currentPage === totalPages) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage < totalPages) { currentPage++; loadPallets(); } + }); + pagination.append(nextBtn); + } + + function fmtDate(v) { + if (!v) return ""; + var s = String(v); + if (s.indexOf("T") > -1) s = s.split("T")[0]; + if (s.indexOf(" ") > -1) s = s.split(" ")[0]; + return s; + } + + $("#pallet-search").on("input", function() { + searchTerm = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + $("#status-filter").on("change", function() { + statusFilter = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + loadPallets(); +}; diff --git a/westech_r2/westech_r2/page/pallet_list/pallet_list.json b/westech_r2/westech_r2/page/pallet_list/pallet_list.json new file mode 100644 index 0000000..d7304c4 --- /dev/null +++ b/westech_r2/westech_r2/page/pallet_list/pallet_list.json @@ -0,0 +1,19 @@ +{ + content: null, + creation: 2026-05-19 13:00:00.000000, + docstatus: 0, + doctype: Page, + idx: 0, + modified: 2026-05-19 13:00:00.000000, + modified_by: Administrator, + module: Westech R2, + name: pallet-list, + owner: Administrator, + page_name: pallet-list, + roles: [], + script: null, + standard: Yes, + style: null, + system_page: 0, + title: Pallet List +} diff --git a/westech_r2/westech_r2/page/pallet_list/pallet_list.py b/westech_r2/westech_r2/page/pallet_list/pallet_list.py new file mode 100644 index 0000000..0a0e433 --- /dev/null +++ b/westech_r2/westech_r2/page/pallet_list/pallet_list.py @@ -0,0 +1,64 @@ +import frappe + +@frappe.whitelist() +def get_pallets(page=1, page_size=100, sort_field="pallet_number", sort_dir="desc", status_filter="", search=""): + page = int(page) + page_size = int(page_size) + offset = (page - 1) * page_size + + conditions = [ + "pallet_number IS NOT NULL", + "pallet_number != ''", + "date_reserved IS NOT NULL", + "customer_number IS NOT NULL", + "customer_number != ''" + ] + + junk = ["", "0", "0000", "N/A", "TBD", "null", "999990", "999995"] + junk_list = "', '".join(junk) + conditions.append("pallet_number NOT IN ('" + junk_list + "')") + conditions.append("pallet_number NOT LIKE '999%'") + conditions.append("pallet_number REGEXP '^[0-9]'") + + if status_filter: + conditions.append("status = '" + frappe.db.escape(status_filter) + "'") + if search: + conditions.append("pallet_number LIKE '%" + frappe.db.escape(search) + "%'") + + where_clause = " AND ".join(conditions) + + total = frappe.db.sql("SELECT COUNT(*) FROM tabPallet WHERE " + where_clause)[0][0] + + pallets = frappe.db.sql("SELECT name, pallet_number, date_reserved, received_date, customer_number, company_name, inbound_weight, tester, description, qty_to_sales, weight_to_sales, finish_date, notes, status FROM tabPallet WHERE " + where_clause + " ORDER BY CAST(pallet_number AS UNSIGNED) " + sort_dir + " LIMIT " + str(page_size) + " OFFSET " + str(offset), as_dict=True) + + empty_pallet = frappe.db.sql("SELECT name, pallet_number, date_reserved, received_date, customer_number, company_name, inbound_weight, tester, description, qty_to_sales, weight_to_sales, finish_date, notes, status FROM tabPallet WHERE date_reserved IS NULL AND (customer_number IS NULL OR customer_number = '') AND pallet_number NOT IN ('" + junk_list + "') AND pallet_number NOT LIKE '999%' AND pallet_number REGEXP '^[0-9]' ORDER BY CAST(pallet_number AS UNSIGNED) DESC LIMIT 1", as_dict=True) + + result = [] + if empty_pallet: + empty_pallet[0]["_is_new"] = True + result.append(empty_pallet[0]) + result.extend(pallets) + + return {"pallets": result, "total": total, "page": page, "page_size": page_size} + +@frappe.whitelist() +def update_pallet(docname, field, value): + pallet = frappe.get_doc("Pallet", docname) + pallet.set(field, value) + pallet.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": "Updated " + field} + +@frappe.whitelist() +def create_pallet(data): + data = frappe.parse_json(data) + pallet = frappe.new_doc("Pallet") + pallet.pallet_number = data.get("pallet_number") + pallet.status = data.get("status", "Received") + pallet.date_reserved = data.get("date_reserved") + for field, value in data.items(): + if field not in ["pallet_number", "status", "date_reserved"] and value: + pallet.set(field, value) + pallet.insert(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "name": pallet.name} diff --git a/westech_r2/westech_r2/page/route-planner/route-planner.html b/westech_r2/westech_r2/page/route-planner/route-planner.html new file mode 100644 index 0000000..0116139 --- /dev/null +++ b/westech_r2/westech_r2/page/route-planner/route-planner.html @@ -0,0 +1,4 @@ +
+

Route Planner

+

Optimize pickup routes for scheduled pickups.

+
diff --git a/westech_r2/westech_r2/page/route-planner/route-planner.js b/westech_r2/westech_r2/page/route-planner/route-planner.js new file mode 100644 index 0000000..9d8ff74 --- /dev/null +++ b/westech_r2/westech_r2/page/route-planner/route-planner.js @@ -0,0 +1,38 @@ +frappe.pages["route-planner"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Route Planner", + single_column: true + }); + + frappe.call({ + method: "westech_r2.api.optimize_routes.get_scheduled_pickups", + callback: function(r) { + if (r.message) { + renderRoutePlanner(page, r.message); + } + } + }); + + function renderRoutePlanner(page, data) { + var h = "
"; + h += "

Route Planner

"; + h += "

Schedule and optimize pickup routes.

"; + h += "
"; + h += ""; + h += "
"; + h += "
"; + $(page.body).html(h); + + $("#optimize-btn").on("click", function() { + frappe.call({ + method: "westech_r2.api.optimize_routes.optimize_routes", + callback: function(r) { + if (r.message) { + frappe.show_alert({message: "Routes optimized", indicator: "green"}); + } + } + }); + }); + } +}; diff --git a/westech_r2/westech_r2/page/route_planner/route_planner.html b/westech_r2/westech_r2/page/route_planner/route_planner.html new file mode 100644 index 0000000..0116139 --- /dev/null +++ b/westech_r2/westech_r2/page/route_planner/route_planner.html @@ -0,0 +1,4 @@ +
+

Route Planner

+

Optimize pickup routes for scheduled pickups.

+
diff --git a/westech_r2/westech_r2/page/route_planner/route_planner.js b/westech_r2/westech_r2/page/route_planner/route_planner.js new file mode 100644 index 0000000..9d8ff74 --- /dev/null +++ b/westech_r2/westech_r2/page/route_planner/route_planner.js @@ -0,0 +1,38 @@ +frappe.pages["route-planner"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: "Route Planner", + single_column: true + }); + + frappe.call({ + method: "westech_r2.api.optimize_routes.get_scheduled_pickups", + callback: function(r) { + if (r.message) { + renderRoutePlanner(page, r.message); + } + } + }); + + function renderRoutePlanner(page, data) { + var h = "
"; + h += "

Route Planner

"; + h += "

Schedule and optimize pickup routes.

"; + h += "
"; + h += ""; + h += "
"; + h += "
"; + $(page.body).html(h); + + $("#optimize-btn").on("click", function() { + frappe.call({ + method: "westech_r2.api.optimize_routes.optimize_routes", + callback: function(r) { + if (r.message) { + frappe.show_alert({message: "Routes optimized", indicator: "green"}); + } + } + }); + }); + } +};