From 7d8d1b13762987a3ff5aaa083c5eb4d92f6178ab Mon Sep 17 00:00:00 2001 From: Westech Admin Date: Thu, 21 May 2026 01:45:30 +0000 Subject: [PATCH] Fix page module paths: move all pages to correct app-level directory, add missing .py files --- .../api/__pycache__/__init__.cpython-312.pyc | Bin 213 -> 0 bytes .../api/__pycache__/sales.cpython-312.pyc | Bin 3856 -> 0 bytes .../service_invoice.cpython-312.pyc | Bin 7079 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 170 -> 0 bytes .../load/__pycache__/__init__.cpython-312.pyc | Bin 175 -> 0 bytes .../load/__pycache__/load.cpython-312.pyc | Bin 1087 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 177 -> 0 bytes .../pallet/__pycache__/pallet.cpython-312.pyc | Bin 685 -> 0 bytes .../customer_records/customer_records.json | 23 + westech_r2/page/load_detail/load-detail.py | 3 + westech_r2/page/load_detail/load_detail.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 179 -> 179 bytes ...on-312.pyc => pallet_list.cpython-312.pyc} | Bin 4720 -> 4720 bytes westech_r2/page/route_planner/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 181 bytes .../page/route_planner/route-planner.py | 3 + .../page/route_planner/route_planner.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 173 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 181 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 197 -> 0 bytes .../customer_record.cpython-312.pyc | Bin 446 -> 0 bytes .../page/customer_intake/__init__.py | 0 .../page/customer_intake/customer-intake.json | 1 + .../page/customer_intake/customer_intake.html | 96 +++ .../page/customer_intake/customer_intake.js | 125 +++ .../page/customer_intake/customer_intake.py | 84 ++ .../customer_records/customer-records.json | 1 + .../customer_records/customer_records.html | 227 +++++ .../page/customer_records/customer_records.py | 85 ++ .../westech_r2/page/ebay-pricing/__init__.py | 0 .../page/ebay-pricing/ebay-pricing.css | 5 + .../page/ebay-pricing/ebay-pricing.html | 8 + .../page/ebay-pricing/ebay-pricing.js | 323 ++++++++ .../page/ebay-pricing/ebay-pricing.json | 26 + .../page/ebay-pricing/ebay-pricing.py | 1 + .../page/ebay-pricing/ebay_pricing.css | 5 + .../page/ebay-pricing/ebay_pricing.html | 8 + .../page/ebay-pricing/ebay_pricing.js | 1 + .../page/ebay-pricing/ebay_pricing.json | 1 + .../page/ebay-pricing/ebay_pricing.py | 1 + .../westech_r2/page/eim_portal/__init__.py | 0 .../westech_r2/page/eim_portal/eim-portal.css | 1 + .../westech_r2/page/eim_portal/eim-portal.js | 4 + .../page/eim_portal/eim-portal.json | 13 + .../westech_r2/page/eim_portal/eim-portal.py | 5 + .../westech_r2/page/eim_portal/eim_portal.js | 7 + .../page/eim_portal/eim_portal.json | 23 + westech_r2/westech_r2/page/intake/__init__.py | 0 westech_r2/westech_r2/page/intake/intake.css | 11 + westech_r2/westech_r2/page/intake/intake.js | 772 ++++++++++++++++++ westech_r2/westech_r2/page/intake/intake.json | 23 + westech_r2/westech_r2/page/intake/intake.py | 5 + .../westech_r2/page/load_detail/__init__.py | 0 .../page/load_detail/load-detail.css | 1 + .../page/load_detail/load-detail.html | 53 ++ .../page/load_detail/load-detail.js | 65 ++ .../page/load_detail/load-detail.json | 18 + .../page/load_detail/load_detail.css | 1 + .../page/load_detail/load_detail.html | 53 ++ .../page/load_detail/load_detail.js | 65 ++ .../page/load_detail/load_detail.json | 18 + .../westech_r2/page/load_update/__init__.py | 0 .../page/load_update/load-update.css | 1 + .../page/load_update/load-update.html | 4 + .../page/load_update/load-update.js | 109 +++ .../page/load_update/load-update.json | 18 + .../page/load_update/load-update.py | 17 + .../page/load_update/load_update.css | 1 + .../page/load_update/load_update.html | 4 + .../page/load_update/load_update.js | 109 +++ .../page/load_update/load_update.json | 18 + .../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 ++ .../westech_r2/page/r2_tracking/__init__.py | 0 .../page/r2_tracking/r2-tracking.css | 1 + .../page/r2_tracking/r2-tracking.js | 4 + .../page/r2_tracking/r2-tracking.json | 13 + .../page/r2_tracking/r2-tracking.py | 5 + .../page/r2_tracking/r2_tracking.js | 7 + .../page/r2_tracking/r2_tracking.json | 23 + .../page/route_planner/route-planner.html | 4 + .../page/route_planner/route-planner.js | 38 + .../page/route_planner/route-planner.json | 14 + .../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/wes-ai/__init__.py | 0 westech_r2/westech_r2/page/wes-ai/wes-ai.css | 1 + westech_r2/westech_r2/page/wes-ai/wes-ai.js | 4 + westech_r2/westech_r2/page/wes-ai/wes-ai.json | 13 + westech_r2/westech_r2/page/wes-ai/wes-ai.py | 5 + westech_r2/westech_r2/page/wes-ai/wes_ai.js | 30 + 100 files changed, 3269 insertions(+) delete mode 100644 westech_r2/api/__pycache__/__init__.cpython-312.pyc delete mode 100644 westech_r2/api/__pycache__/sales.cpython-312.pyc delete mode 100644 westech_r2/api/__pycache__/service_invoice.cpython-312.pyc delete mode 100644 westech_r2/doctype/__pycache__/__init__.cpython-312.pyc delete mode 100644 westech_r2/doctype/load/__pycache__/__init__.cpython-312.pyc delete mode 100644 westech_r2/doctype/load/__pycache__/load.cpython-312.pyc delete mode 100644 westech_r2/doctype/pallet/__pycache__/__init__.cpython-312.pyc delete mode 100644 westech_r2/doctype/pallet/__pycache__/pallet.cpython-312.pyc create mode 100644 westech_r2/page/customer_records/customer_records.json create mode 100644 westech_r2/page/load_detail/load-detail.py create mode 100644 westech_r2/page/load_detail/load_detail.py rename westech_r2/page/pallet_list/__pycache__/{pallet-list.cpython-312.pyc => pallet_list.cpython-312.pyc} (97%) create mode 100644 westech_r2/page/route_planner/__init__.py create mode 100644 westech_r2/page/route_planner/__pycache__/__init__.cpython-312.pyc create mode 100644 westech_r2/page/route_planner/route-planner.py create mode 100644 westech_r2/page/route_planner/route_planner.py delete mode 100644 westech_r2/westech_r2/__pycache__/__init__.cpython-312.pyc delete mode 100644 westech_r2/westech_r2/doctype/__pycache__/__init__.cpython-312.pyc delete mode 100644 westech_r2/westech_r2/doctype/customer_record/__pycache__/__init__.cpython-312.pyc delete mode 100644 westech_r2/westech_r2/doctype/customer_record/__pycache__/customer_record.cpython-312.pyc create mode 100644 westech_r2/westech_r2/page/customer_intake/__init__.py create mode 100644 westech_r2/westech_r2/page/customer_intake/customer-intake.json create mode 100644 westech_r2/westech_r2/page/customer_intake/customer_intake.html create mode 100644 westech_r2/westech_r2/page/customer_intake/customer_intake.js create mode 100644 westech_r2/westech_r2/page/customer_intake/customer_intake.py create mode 100644 westech_r2/westech_r2/page/customer_records/customer-records.json create mode 100644 westech_r2/westech_r2/page/customer_records/customer_records.html create mode 100644 westech_r2/westech_r2/page/customer_records/customer_records.py create mode 100644 westech_r2/westech_r2/page/ebay-pricing/__init__.py create mode 100644 westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.css create mode 100644 westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.html create mode 100644 westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.js create mode 100644 westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.json create mode 100644 westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.py create mode 100644 westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.css create mode 100644 westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.html create mode 120000 westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.js create mode 120000 westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.json create mode 100644 westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.py create mode 100644 westech_r2/westech_r2/page/eim_portal/__init__.py create mode 100644 westech_r2/westech_r2/page/eim_portal/eim-portal.css create mode 100644 westech_r2/westech_r2/page/eim_portal/eim-portal.js create mode 100644 westech_r2/westech_r2/page/eim_portal/eim-portal.json create mode 100644 westech_r2/westech_r2/page/eim_portal/eim-portal.py create mode 100644 westech_r2/westech_r2/page/eim_portal/eim_portal.js create mode 100644 westech_r2/westech_r2/page/eim_portal/eim_portal.json create mode 100644 westech_r2/westech_r2/page/intake/__init__.py create mode 100644 westech_r2/westech_r2/page/intake/intake.css create mode 100644 westech_r2/westech_r2/page/intake/intake.js create mode 100644 westech_r2/westech_r2/page/intake/intake.json create mode 100644 westech_r2/westech_r2/page/intake/intake.py create mode 100644 westech_r2/westech_r2/page/load_detail/__init__.py create mode 100644 westech_r2/westech_r2/page/load_detail/load-detail.css 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_detail/load_detail.css 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.css 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/load_update/load_update.css 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/r2_tracking/__init__.py create mode 100644 westech_r2/westech_r2/page/r2_tracking/r2-tracking.css create mode 100644 westech_r2/westech_r2/page/r2_tracking/r2-tracking.js create mode 100644 westech_r2/westech_r2/page/r2_tracking/r2-tracking.json create mode 100644 westech_r2/westech_r2/page/r2_tracking/r2-tracking.py create mode 100644 westech_r2/westech_r2/page/r2_tracking/r2_tracking.js create mode 100644 westech_r2/westech_r2/page/r2_tracking/r2_tracking.json 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.json 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.json create mode 100644 westech_r2/westech_r2/page/wes-ai/__init__.py create mode 100644 westech_r2/westech_r2/page/wes-ai/wes-ai.css create mode 100644 westech_r2/westech_r2/page/wes-ai/wes-ai.js create mode 100644 westech_r2/westech_r2/page/wes-ai/wes-ai.json create mode 100644 westech_r2/westech_r2/page/wes-ai/wes-ai.py create mode 100644 westech_r2/westech_r2/page/wes-ai/wes_ai.js diff --git a/westech_r2/api/__pycache__/__init__.cpython-312.pyc b/westech_r2/api/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 5dd511c12dc20ef002d5ef27e2e760fef46128f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213 zcmX@j%ge<81dDaKvXp@IV-N=hn4pZ$0zk%eh7^Vr#vF!R#wbQchDs()=9eI8O~zZS z#fdqo#eSMhxA@9ai%U|IGvbSk^b!j)iqx(T|VM%*!l^kJl@x{Ka9Do1apelWJGQ0W_5nh>Jmt Q56p~=jL#Spir9c00EFx|^8f$< diff --git a/westech_r2/api/__pycache__/sales.cpython-312.pyc b/westech_r2/api/__pycache__/sales.cpython-312.pyc deleted file mode 100644 index 57d58b9085af199f032b7f0599618cc6c9d46acf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3856 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 TZ*)UC^6Wc3q4TRMpPQ fu*uC&Da}c>D`Ewj%m~EAAjU^#Mn=XWW*`dynj9lIY~;;_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(&9YQj;#udF4I(YR(%?gFDsQH2y6hCA%B)P!I=FVPBq0Zv0Zqcx z%?swHN&XOs%L|vs33JOZO@a3gR<>%&pb%!gCyYGIz|(}alcXFd6Xs3=DPiJbEf++^ zIOhYeC7ik<$j8|bsN~VGEJ0Yizyql-Ofn1@aG|G=d%Dm`5eYK`9v4JdwHRaS#;)t0 z4g9#sz^^rYpk)sG{Q3~`DE6f+^Y?&ph~j|W`Ws43UX|e2tt>;Yti_IfUPrh{EsrAji z@Vx!3{bJ+I?W4Wd>tF2~r!8b(nM)buX;gi+h4@=U*A!lr?#y1#3NlV%gIl;|d<<|Sw71BHt9%TtR>Qj;^{i;R$&1&QgY`bGJrC8_ZRIf;3BsYUwn r@tJv5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!^3l)8&rQ`&D@rUV zNYzg*D#%N%DA7$y%}dVE2MQJIm!}q&q$X#?7a8GT#>Z#oWtPOp>lIY~;;_lhPbtkw YwJTx;8qNsB#UREl;|d<<|Sw71BHt9%TtR>Qj;^{i;QqEQ}UBbDuH_A<1_OzOXB183Mzkb f*yQG?l;)(`6|n*>VFco05aS~=BO_xGGmr%U5%Mno diff --git a/westech_r2/westech_r2/doctype/customer_record/__pycache__/__init__.cpython-312.pyc b/westech_r2/westech_r2/doctype/customer_record/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 00f58a235a1a8043515e0b32ce78dda13aa8d2ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 197 zcmX@j%ge<81Vx5?Ss?l`h(HIQS%4zb87dhx8U0o=6fpsLpFwJVrRZnm=cekX6(trF zr0S;@738H>l;|d<<|Sw71BHt9%TtR>Qj;^{i;QqEQ}UBbDuH^FON&c@Mis>ur6%VW urRc}UXXa&=#K-FuRQ}?y$<0qG%}KQ@Vg*{t2*kx8#z$sGM#ds$APWG!{xyyO diff --git a/westech_r2/westech_r2/doctype/customer_record/__pycache__/customer_record.cpython-312.pyc b/westech_r2/westech_r2/doctype/customer_record/__pycache__/customer_record.cpython-312.pyc deleted file mode 100644 index 241c131be24f52068f31e5192b7656cb9496257f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmZ`#yH3ME5Ztv%WI~b-J^{%>*n%3-fJ8?@h1{IX-J%Hm;%p1j=L6{S4T$fc;s+wP zRCGutO)B<$ra@why_vn6)!e*KCL`d|N7K7EK0gfktw9gkeFjTVpfG_HBSdiE0+h1= zUa^qppUR+m+tlD;CDYjx?n zjVDAFrzAu(5+co2ofte8;-QWcd-DRV*}1t7XRHlxbzBq_k}fiOst#``le3UVW%x*C zMRF$e@jp=IvYNA2_BMp>eEj7>G1n%Uu6Ybf!xpf@fi_uob7OwjdI{J!B>`{m;?O27 qyI|X(PO`&j^* diff --git a/westech_r2/westech_r2/page/customer_intake/__init__.py b/westech_r2/westech_r2/page/customer_intake/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/westech_r2/page/customer_intake/customer-intake.json b/westech_r2/westech_r2/page/customer_intake/customer-intake.json new file mode 100644 index 0000000..b2434e2 --- /dev/null +++ b/westech_r2/westech_r2/page/customer_intake/customer-intake.json @@ -0,0 +1 @@ +{"creation":"2026-05-20 15:00:00.000000","docstatus":0,"doctype":"Page","idx":0,"module":"westech_r2","name":"customer-intake","page_name":"customer-intake","roles":[],"script":null,"standard":"Yes","style":null,"system_page":0,"title":"Customer Intake"} diff --git a/westech_r2/westech_r2/page/customer_intake/customer_intake.html b/westech_r2/westech_r2/page/customer_intake/customer_intake.html new file mode 100644 index 0000000..b475162 --- /dev/null +++ b/westech_r2/westech_r2/page/customer_intake/customer_intake.html @@ -0,0 +1,96 @@ +
+
+
+

Customer Intake

+
+
+
+
+ + +
+
+
+ +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + + +
+
+
diff --git a/westech_r2/westech_r2/page/customer_intake/customer_intake.js b/westech_r2/westech_r2/page/customer_intake/customer_intake.js new file mode 100644 index 0000000..4952da8 --- /dev/null +++ b/westech_r2/westech_r2/page/customer_intake/customer_intake.js @@ -0,0 +1,125 @@ +frappe.pages["customer-intake"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({parent: wrapper, title: __("Customer Intake"), single_column: true}); + var content = frappe.render_template("customer-intake", {}); + $(page.body).append(content); + + var currentCustomer = null; + var searchTimer = null; + + function clearForm() { + currentCustomer = null; + $("#cust-name, #cust-number, #cust-phone, #cust-address, #cust-city, #cust-state, #cust-zip, #cust-contacts, #cust-email, #cust-hours").val(""); + $("#search-results").empty(); + $("#no-match").hide(); + $("#cust-status").text(""); + } + + function fillForm(c) { + currentCustomer = c; + $("#cust-name").val(c.customer_name || ""); + $("#cust-number").val(c.customer_number || ""); + $("#cust-phone").val(c.phone || c.address_phone || ""); + $("#cust-address").val(c.address_line1 || ""); + $("#cust-city").val(c.city || ""); + $("#cust-state").val(c.state || ""); + $("#cust-zip").val(c.pincode || ""); + $("#cust-contacts").val(c.contact_persons || ""); + $("#cust-email").val(c.email_id || ""); + $("#cust-hours").val(c.hours_of_operation || ""); + $("#cust-status").text("Selected: " + (c.customer_name || c.name)); + $("#no-match").hide(); + } + + function doSearch() { + var q = $("#intake-search").val().trim(); + if (q.length < 2) { $("#search-results").empty(); return; } + frappe.call({ + method: "westech_r2.page.customer-intake.customer-intake.search_customers", + args: {q: q}, + callback: function(r) { + var list = $("#search-results").empty(); + if (r.message && r.message.length) { + r.message.forEach(function(c) { + var item = $('
') + .html('' + frappe.utils.escape_html(c.customer_name || c.name) + ' ' + + (c.address_line1 ? '
' + frappe.utils.escape_html(c.address_line1) : '') + + (c.city ? ', ' + c.city : '') + + (c.phone ? '
' + c.phone + '' : '')); + item.on("click", function() { fillForm(c); }); + list.append(item); + }); + $("#no-match").hide(); + } else { + $("#no-match").show(); + } + } + }); + } + + $("#intake-search").on("input", function() { + clearTimeout(searchTimer); + searchTimer = setTimeout(doSearch, 300); + }); + + $("#btn-add-new").click(function() { + clearForm(); + $("#cust-name").val($("#intake-search").val()); + $("#cust-status").text("Adding new customer..."); + }); + + $("#btn-save-cust").click(function() { + var data = { + customer_name: $("#cust-name").val(), + customer_number: $("#cust-number").val(), + phone: $("#cust-phone").val(), + address_line1: $("#cust-address").val(), + city: $("#cust-city").val(), + state: $("#cust-state").val(), + pincode: $("#cust-zip").val(), + contact_persons: $("#cust-contacts").val(), + email_id: $("#cust-email").val(), + hours_of_operation: $("#cust-hours").val() + }; + if (currentCustomer && currentCustomer.name) { + data.name = currentCustomer.name; + } + frappe.call({ + method: "westech_r2.page.customer-intake.customer-intake.create_customer_from_intake", + args: {data: JSON.stringify(data)}, + callback: function(r) { + if (r.message && r.message.status === "ok") { + currentCustomer = {name: r.message.customer, customer_name: data.customer_name}; + $("#cust-status").text("Saved: " + r.message.customer); + frappe.show_alert("Customer saved", 3); + } else { + frappe.show_alert("Error saving customer", 5); + } + } + }); + }); + + $("#btn-create-pallet").click(function() { + if (!currentCustomer || !currentCustomer.name) { + frappe.msgprint("Please select or save a customer first."); + return; + } + frappe.call({ + method: "westech_r2.page.customer-intake.customer-intake.create_pallet", + args: { + data: JSON.stringify({ + customer: currentCustomer.name, + customer_number: $("#cust-number").val(), + data_status: $("#pallet-data-status").val(), + status: $("#pallet-status").val(), + inbound_weight: $("#pallet-weight").val() + }) + }, + callback: function(r) { + if (r.message && r.message.status === "ok") { + frappe.msgprint("Pallet created: " + r.message.pallet); + $("#cust-status").text("Pallet: " + r.message.pallet); + } + } + }); + }); +}; diff --git a/westech_r2/westech_r2/page/customer_intake/customer_intake.py b/westech_r2/westech_r2/page/customer_intake/customer_intake.py new file mode 100644 index 0000000..544f5be --- /dev/null +++ b/westech_r2/westech_r2/page/customer_intake/customer_intake.py @@ -0,0 +1,84 @@ +import frappe +from frappe import _ + +@frappe.whitelist() +def search_customers(q=""): + if not q or len(q) < 2: + return [] + q = q.strip().lower() + customers = frappe.db.sql(""" + SELECT c.name, c.customer_name, c.customer_number, c.phone, c.email_id, + a.address_line1, a.city, a.state, a.pincode + FROM tabCustomer c + LEFT JOIN tabDynamic Link dl ON dl.link_doctype = 'Customer' AND dl.link_name = c.name AND dl.parenttype = 'Address' + LEFT JOIN tabAddress a ON a.name = dl.parent + WHERE LOWER(c.customer_name) LIKE %s OR LOWER(c.customer_number) LIKE %s OR LOWER(c.phone) LIKE %s + ORDER BY c.customer_name + LIMIT 20 + """, ("%" + q + "%", "%" + q + "%", "%" + q + "%"), as_dict=True) + return customers + +@frappe.whitelist() +def get_customer(name): + if not name: + return {} + cust = frappe.get_doc("Customer", name) + result = cust.as_dict() + addr = frappe.db.sql(""" + SELECT a.address_line1, a.city, a.state, a.pincode, a.phone + FROM tabAddress a + JOIN tabDynamic Link dl ON dl.parent = a.name AND dl.link_doctype = 'Customer' AND dl.link_name = %s + LIMIT 1 + """, (name,), as_dict=True) + if addr: + result.update({ + "address_line1": addr[0].address_line1, + "city": addr[0].city, + "state": addr[0].state, + "pincode": addr[0].pincode, + "address_phone": addr[0].phone + }) + return result + +@frappe.whitelist() +def create_customer_from_intake(data): + data = frappe.parse_json(data) + if not data.get("customer_name"): + frappe.throw(_("Customer name required")) + customer = frappe.new_doc("Customer") + customer.customer_name = data.get("customer_name") + customer.customer_group = data.get("customer_group", "IT Recycling") + customer.customer_type = "Company" + customer.customer_number = data.get("customer_number") + customer.phone = data.get("phone") + customer.email_id = data.get("email_id") + customer.legacy_notes = data.get("legacy_notes") + customer.hours_of_operation = data.get("hours_of_operation") + customer.contact_persons = data.get("contact_persons") + customer.save() + if data.get("address_line1") or data.get("city"): + addr = frappe.new_doc("Address") + addr.address_title = customer.customer_name + addr.address_type = "Billing" + addr.address_line1 = data.get("address_line1", "Unknown") + addr.city = data.get("city", "Unknown") + addr.state = data.get("state", "") + addr.pincode = data.get("pincode", "") + addr.country = "United States" + addr.append("links", {"link_doctype": "Customer", "link_name": customer.name}) + addr.save() + return {"status": "ok", "customer": customer.name} + +@frappe.whitelist() +def create_pallet(data): + data = frappe.parse_json(data) + if not data.get("customer"): + frappe.throw(_("Customer required")) + pallet = frappe.new_doc("Pallet") + pallet.customer = data.get("customer") + pallet.customer_number = data.get("customer_number") + pallet.data_status = data.get("data_status", "D0") + pallet.status = data.get("status", "Received") + pallet.inbound_weight = data.get("inbound_weight", "") + pallet.save() + return {"status": "ok", "pallet": pallet.name} diff --git a/westech_r2/westech_r2/page/customer_records/customer-records.json b/westech_r2/westech_r2/page/customer_records/customer-records.json new file mode 100644 index 0000000..1fbb98a --- /dev/null +++ b/westech_r2/westech_r2/page/customer_records/customer-records.json @@ -0,0 +1 @@ +{"content": null,"creation": "2026-05-20 22:00:00.000000","docstatus": 0,"doctype": "Page","idx": 0,"modified": "2026-05-20 22:00:00.000000","modified_by": "Administrator","module": "Westech R2","name": "customer-records","owner": "Administrator","page_name": "customer-records","roles": [{"doctype": "Has Role","idx": 1,"name": "a80mopj93i","parent": "customer-records","parentfield": "roles","parenttype": "Page","role": "All"}],"script": null,"standard": "Yes","style": null,"system_page": 0,"title": "Customer Records"} diff --git a/westech_r2/westech_r2/page/customer_records/customer_records.html b/westech_r2/westech_r2/page/customer_records/customer_records.html new file mode 100644 index 0000000..fd9d8f2 --- /dev/null +++ b/westech_r2/westech_r2/page/customer_records/customer_records.html @@ -0,0 +1,227 @@ + + +
+

Modify Records

+ +
+ + + 0 of 0 + + + + + + + +
+ +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
diff --git a/westech_r2/westech_r2/page/customer_records/customer_records.py b/westech_r2/westech_r2/page/customer_records/customer_records.py new file mode 100644 index 0000000..008840e --- /dev/null +++ b/westech_r2/westech_r2/page/customer_records/customer_records.py @@ -0,0 +1,85 @@ +import frappe + +@frappe.whitelist() +def get_records(): + # For now return Lead records mapped to form fields + leads = frappe.db.sql(""" + SELECT name, company_name, email_id, mobile_no, phone, address_line1, city, state, pincode, + title, status, industry, source + FROM tabLead + ORDER BY creation DESC + LIMIT 1000 + """, as_dict=True) + result = [] + for l in leads: + result.append({ + "name": l.name, + "additional_numbers": "", + "field_star": l.status or "", + "customer_address": l.address_line1 or "", + "any_letter": l.title or "", + "city": l.city or "", + "field_e": l.email_id or "", + "zip": l.pincode or "", + "company_name": l.company_name or "", + "contacted_date": "", + "contact_persons": l.title or "", + "follow_up_date": "", + "email_address": l.email_id or "", + "last_pu_date": "", + "contact_numbers": (l.phone or "") + "\n" + (l.mobile_no or ""), + "hours_operation": l.industry or "", + "comments": l.source or "" + }) + return result + +@frappe.whitelist() +def save_record(data): + data = frappe.parse_json(data) + # For now just return OK - Lead update can be wired later + return {"status": "ok", "message": "Saved " + (data.get("name") or "")} + +@frappe.whitelist() +def delete_record(name): + # For now return OK + return {"status": "ok", "message": "Deleted " + name} + +@frappe.whitelist() +def search_records(field, value): + leads = frappe.db.sql(""" + SELECT name, company_name, email_id, mobile_no, phone, address_line1, city, state, pincode, + title, status, industry, source + FROM tabLead + WHERE LOWER(company_name) LIKE %s + OR LOWER(title) LIKE %s + OR LOWER(address_line1) LIKE %s + OR LOWER(city) LIKE %s + OR LOWER(pincode) LIKE %s + OR LOWER(email_id) LIKE %s + OR LOWER(phone) LIKE %s + OR LOWER(mobile_no) LIKE %s + ORDER BY creation DESC + LIMIT 100 + """, tuple(["%" + value + "%"] * 8), as_dict=True) + result = [] + for l in leads: + result.append({ + "name": l.name, + "additional_numbers": "", + "field_star": l.status or "", + "customer_address": l.address_line1 or "", + "any_letter": l.title or "", + "city": l.city or "", + "field_e": l.email_id or "", + "zip": l.pincode or "", + "company_name": l.company_name or "", + "contacted_date": "", + "contact_persons": l.title or "", + "follow_up_date": "", + "email_address": l.email_id or "", + "last_pu_date": "", + "contact_numbers": (l.phone or "") + "\n" + (l.mobile_no or ""), + "hours_operation": l.industry or "", + "comments": l.source or "" + }) + return result diff --git a/westech_r2/westech_r2/page/ebay-pricing/__init__.py b/westech_r2/westech_r2/page/ebay-pricing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.css b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.css new file mode 100644 index 0000000..8b27534 --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.css @@ -0,0 +1,5 @@ +.badge-fresh { background-color: #28a745; } +.badge-aging { background-color: #ffc107; color: #212529; } +.badge-expired { background-color: #dc3545; } +.badge-needs { background-color: #fd7e14; } +.badge-error { background-color: #6c757d; } diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.html b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.html new file mode 100644 index 0000000..4015bfb --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.html @@ -0,0 +1,8 @@ + +
diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.js b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.js new file mode 100644 index 0000000..1414078 --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.js @@ -0,0 +1,323 @@ +frappe.pages['ebay-pricing'].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: __('eBay Pricing'), + single_column: true + }); + + let $container = $(` +
+
+
+
+ +
+ + + + +
+
+
+
+
+ + + +
+
+
+
+
+
+

Apply Pricing to Inventory

+
+ +
+ + +
+
+
+
Pricing Status
+
+

Click Apply All to see stats

+
+
+
+
+
+
+
+ +

Search for a model or run batch pricing

+
+
+
`).appendTo(page.main); + + // Load item dropdown + load_item_dropdown(); + + // Event handlers + $container.find('#ebay-search-btn').on('click', function() { + let query = $container.find('#ebay-search-input').val().trim(); + if (!query) { + frappe.msgprint(__('Enter a model to search')); + return; + } + search_ebay(query); + }); + + $container.find('#ebay-search-input').on('keypress', function(e) { + if (e.which === 13) { + $container.find('#ebay-search-btn').trigger('click'); + } + }); + + $container.find('#ebay-batch-btn').on('click', function() { + let size = $container.find('#ebay-batch-size').val(); + run_batch(size); + }); + + $container.find('#ebay-apply-btn').on('click', function() { + let item = $container.find('#ebay-apply-item').val(); + if (!item) { + frappe.msgprint(__('Select an Item first')); + return; + } + apply_pricing(item); + }); + + $container.find('#ebay-apply-all-btn').on('click', function() { + apply_pricing_all(); + }); + + function load_item_dropdown() { + frappe.call({ + method: 'frappe.client.get_list', + args: { + doctype: 'Item', + filters: { + 'disabled': 0, + 'item_group': ['in', ['Laptop', 'Desktop', 'Tablet', 'Phone', 'Workstation']] + }, + fields: ['name', 'item_name'], + limit: 1000 + }, + callback: function(r) { + if (r.message) { + let $select = $container.find('#ebay-apply-item'); + r.message.forEach(item => { + $select.append(``); + }); + } + } + }); + } + + function search_ebay(query) { + frappe.call({ + method: 'westech_r2.api.ebay_pricing.search_model', + args: { query: query }, + freeze: true, + freeze_message: __('Searching eBay sold listings...'), + callback: function(r) { + if (r.message && r.message.results) { + render_results(r.message); + } else { + let msg = (r.message && r.message.message) || __('No results found'); + frappe.msgprint(msg); + } + } + }); + } + + function run_batch(size) { + frappe.call({ + method: 'westech_r2.api.ebay_pricing.run_batch', + args: { batch_size: size }, + freeze: true, + freeze_message: __('Running batch pricing...'), + callback: function(r) { + if (r.message) { + frappe.msgprint(__('Batch complete: {0} priced, {1} failed, {2} skipped', + [r.message.priced, r.message.failed, r.message.skipped])); + load_recent_pricing(); + } + } + }); + } + + function apply_pricing(item_code) { + frappe.call({ + method: 'westech_r2.api.ebay_pricing.batch_apply_pricing', + args: { item_code: item_code }, + freeze: true, + freeze_message: __('Applying pricing to Serial Nos...'), + callback: function(r) { + if (r.message) { + render_pricing_stats(r.message); + frappe.msgprint(__('Pricing applied: {0} priced, {1} commodity, {2} needs grading', + [r.message.priced, r.message.commodity, r.message.needs_grading])); + } + } + }); + } + + function apply_pricing_all() { + frappe.call({ + method: 'westech_r2.api.ebay_pricing.batch_apply_pricing', + args: { batch_size: 1000 }, + freeze: true, + freeze_message: __('Applying pricing to all Serial Nos...'), + callback: function(r) { + if (r.message) { + render_pricing_stats(r.message); + frappe.msgprint(__('Batch pricing applied: {0} priced, {1} commodity, {2} needs grading, {3} errors', + [r.message.priced, r.message.commodity, r.message.needs_grading, r.message.errors])); + } + } + }); + } + + function render_pricing_stats(stats) { + let html = ` + + + + + + +
Priced${stats.priced || 0}
Commodity${stats.commodity || 0}
Needs Grading${stats.needs_grading || 0}
Needs Price Point${stats.needs_price_point || 0}
Errors${stats.errors || 0}
+ `; + $container.find('#pricing-stats').html(html); + } + + function render_results(data) { + let $area = $container.find('#ebay-results-area').empty(); + if (!data.results || !data.results.length) { + $area.html(`
No results
`); + return; + } + + let html = ` + + + + + + + + `; + data.results.forEach(item => { + html += ` + + + + + + `; + }); + html += `
TitlePriceConditionSoldShipping
${frappe.utils.escape_html(item.title || '')}$${(item.price || 0).toFixed(2)}${frappe.utils.escape_html(item.condition || '')}${item.sold || ''}${item.shipping || ''}
`; + + if (data.pricing) { + html += `
+

Pricing Summary

+
+
Low: $${data.pricing.price_low}
+
High: $${data.pricing.price_high}
+
Average: $${data.pricing.price_average}
+
Median: $${data.pricing.price_auction}
+
+
+
Source: ${data.pricing.source}
+
Samples: ${data.pricing.sample_count}
+
+
`; + } + + $area.html(html); + } + + function load_recent_pricing() { + frappe.call({ + method: 'westech_r2.api.ebay_pricing.get_recent_pricing', + args: { limit: 50 }, + callback: function(r) { + if (r.message) { + render_pricing_grid(r.message); + } + } + }); + } + + function render_pricing_grid(items) { + let $area = $container.find('#ebay-results-area'); + if (!items || !items.length) { + $area.html(`
No pricing data yet
`); + return; + } + + let html = `

Recent Pricing Results

+ + + + + + + + + + + + + + `; + + items.forEach(row => { + let status_class = 'badge-needs'; + if (row.pricing_status === 'Priced') status_class = 'badge-fresh'; + else if (row.pricing_status === 'Manual Override') status_class = 'badge-fresh'; + else if (row.pricing_status === 'Expired') status_class = 'badge-expired'; + else if (row.pricing_status === 'Error') status_class = 'badge-error'; + + let age = row.days_since_pricing || 0; + let age_badge = age < 90 ? 'badge-fresh' : (age < 120 ? 'badge-aging' : 'badge-expired'); + + html += ` + + + + + + + + + + + `; + }); + + html += `
ManufacturerModelStatusAgeLowHighAvgSamplesSourceLast Priced
${frappe.utils.escape_html(row.manufacturer || '')}${frappe.utils.escape_html(row.model || '')}${row.pricing_status}${age} days$${row.price_low || ''}$${row.price_high || ''}$${row.price_average || ''}${row.sample_count || ''}${row.source || ''}${frappe.datetime.str_to_user(row.scraped_at) || ''}
`; + $area.html(html); + } + + load_recent_pricing(); +}; diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.json b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.json new file mode 100644 index 0000000..ab9d81b --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.json @@ -0,0 +1,26 @@ +{ + "creation": "2026-05-17 05:30:00.000000", + "docstatus": 0, + "doctype": "Page", + "icon": "fa fa-tags", + "modified": "2026-05-17 05:30:00.000000", + "modified_by": "Administrator", + "module": "Westech R2", + "name": "ebay-pricing", + "owner": "Administrator", + "page_name": "ebay-pricing", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "Stock User" + }, + { + "role": "Sales User" + } + ], + "standard": "Yes", + "system_page": 0, + "title": "eBay Pricing" +} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.py b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.py new file mode 100644 index 0000000..4053179 --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay-pricing.py @@ -0,0 +1 @@ +# eBay Pricing desk page diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.css b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.css new file mode 100644 index 0000000..8b27534 --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.css @@ -0,0 +1,5 @@ +.badge-fresh { background-color: #28a745; } +.badge-aging { background-color: #ffc107; color: #212529; } +.badge-expired { background-color: #dc3545; } +.badge-needs { background-color: #fd7e14; } +.badge-error { background-color: #6c757d; } diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.html b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.html new file mode 100644 index 0000000..4015bfb --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.html @@ -0,0 +1,8 @@ + +
diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.js b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.js new file mode 120000 index 0000000..8cd44b0 --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.js @@ -0,0 +1 @@ +ebay-pricing.js \ No newline at end of file diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.json b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.json new file mode 120000 index 0000000..d388217 --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.json @@ -0,0 +1 @@ +ebay-pricing.json \ No newline at end of file diff --git a/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.py b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.py new file mode 100644 index 0000000..4053179 --- /dev/null +++ b/westech_r2/westech_r2/page/ebay-pricing/ebay_pricing.py @@ -0,0 +1 @@ +# eBay Pricing desk page diff --git a/westech_r2/westech_r2/page/eim_portal/__init__.py b/westech_r2/westech_r2/page/eim_portal/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/westech_r2/page/eim_portal/eim-portal.css b/westech_r2/westech_r2/page/eim_portal/eim-portal.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/westech_r2/westech_r2/page/eim_portal/eim-portal.css @@ -0,0 +1 @@ + diff --git a/westech_r2/westech_r2/page/eim_portal/eim-portal.js b/westech_r2/westech_r2/page/eim_portal/eim-portal.js new file mode 100644 index 0000000..9d84ac1 --- /dev/null +++ b/westech_r2/westech_r2/page/eim_portal/eim-portal.js @@ -0,0 +1,4 @@ +frappe.pages["eim-portal"].on_page_load = function(wrapper) { + wrapper.innerHTML = '

Redirecting to EIM Device Portal...

'; + setTimeout(function() { window.location.href = "https://eim.diagalon.com"; }, 500); +}; diff --git a/westech_r2/westech_r2/page/eim_portal/eim-portal.json b/westech_r2/westech_r2/page/eim_portal/eim-portal.json new file mode 100644 index 0000000..c06f7bd --- /dev/null +++ b/westech_r2/westech_r2/page/eim_portal/eim-portal.json @@ -0,0 +1,13 @@ +{ + "creation": "2026-05-09 14:00:00", + "docstatus": 0, + "doctype": "Page", + "idx": 0, + "modified": "2026-05-09 14:00:00", + "modified_by": "Administrator", + "module": "Westech R2", + "name": "eim-portal", + "owner": "Administrator", + "standard": "Yes", + "title": "EIM Device Portal" +} diff --git a/westech_r2/westech_r2/page/eim_portal/eim-portal.py b/westech_r2/westech_r2/page/eim_portal/eim-portal.py new file mode 100644 index 0000000..9d9e209 --- /dev/null +++ b/westech_r2/westech_r2/page/eim_portal/eim-portal.py @@ -0,0 +1,5 @@ +import frappe + +def get_context(context): + frappe.local.flags.redirect_location = "https://eim.diagalon.com" + raise frappe.Redirect diff --git a/westech_r2/westech_r2/page/eim_portal/eim_portal.js b/westech_r2/westech_r2/page/eim_portal/eim_portal.js new file mode 100644 index 0000000..e5cbdea --- /dev/null +++ b/westech_r2/westech_r2/page/eim_portal/eim_portal.js @@ -0,0 +1,7 @@ +frappe.pages['eim-portal'].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: 'EIM Device Portal', + single_column: true + }); +} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/eim_portal/eim_portal.json b/westech_r2/westech_r2/page/eim_portal/eim_portal.json new file mode 100644 index 0000000..1330152 --- /dev/null +++ b/westech_r2/westech_r2/page/eim_portal/eim_portal.json @@ -0,0 +1,23 @@ +{ + "content": null, + "creation": "2026-05-09 14:00:00", + "docstatus": 0, + "doctype": "Page", + "idx": 0, + "modified": "2026-05-09 15:09:48.653878", + "modified_by": "Administrator", + "module": "Westech R2", + "name": "eim-portal", + "owner": "Administrator", + "page_name": "eim-portal", + "roles": [ + { + "role": "All" + } + ], + "script": null, + "standard": "Yes", + "style": null, + "system_page": 0, + "title": "EIM Device Portal" +} \ No newline at end of file diff --git a/westech_r2/westech_r2/page/intake/__init__.py b/westech_r2/westech_r2/page/intake/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/westech_r2/page/intake/intake.css b/westech_r2/westech_r2/page/intake/intake.css new file mode 100644 index 0000000..c5f45ab --- /dev/null +++ b/westech_r2/westech_r2/page/intake/intake.css @@ -0,0 +1,11 @@ +.intake-station .card { border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; } +.intake-station .card-header { padding: 15px; } +.intake-station .card-body { padding: 20px; } +.intake-station .form-group { margin-bottom: 15px; } +.intake-station .form-control { border-radius: 4px; padding: 8px 12px; font-size: 16px; } +.intake-station .form-control:focus { border-color: #6f42c1; box-shadow: 0 0 0 0.2rem rgba(111,66,193,0.25); } +.intake-station label { font-weight: 600; margin-bottom: 4px; } +.intake-station h5 { margin-bottom: 15px; padding-bottom: 8px; border-bottom: 2px solid #e0e0e0; } +.intake-station .table th { background: #f8f9fa; } +.intake-station .btn-primary { background: linear-gradient(135deg, #6f42c1, #28a745) !important; border: none !important; } +.intake-station .label { font-size: 0.85em; } \ No newline at end of file diff --git a/westech_r2/westech_r2/page/intake/intake.js b/westech_r2/westech_r2/page/intake/intake.js new file mode 100644 index 0000000..0242040 --- /dev/null +++ b/westech_r2/westech_r2/page/intake/intake.js @@ -0,0 +1,772 @@ +frappe.pages['intake'].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: 'Intake Station', + single_column: true + }); + + page.set_primary_action('New Intake', function() { + show_intake_form(); + }, 'add'); + + page.add_inner_button('Refresh', function() { + load_recent_pallets(); + }); + + $(wrapper).find('.layout-main-section').html(` +
+ + +
+
+
+
Recent Pallets
+
+
+ + + + + + + + + + + + + + + + +
StatusCustomer #DriverReceivedRED/R2ItemsWeightActions
Loading...
+
+
+
+
+ `); + + // Build ERPNext Link controls for Customer Number and Supplier + setup_link_controls(); + + set_today_date(); + load_recent_pallets(); + + $('#received_date').on('change', function() { + var d = new Date($(this).val() + 'T12:00:00'); + var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']; + $('#weekday').val(days[d.getDay()] || ''); + }); + + $('#intake-form').on('submit', function(e) { + e.preventDefault(); + save_pallet(); + }); + + $('#btn-cancel').on('click', function() { + $('#intake-form-container').hide(); + $('#recent-pallets').show(); + clear_form(); + }); + + $('#btn-print-labels').on('click', function() { + print_labels(); + }); +}; + +// ── ERPNext Link Controls ────────────────────────────────────────────── + +var customer_number_control = null; +var supplier_control = null; + +function setup_link_controls() { + // Customer Number — Link to Supplier, searching by name (which IS the customer number) + customer_number_control = frappe.ui.form.make_control({ + parent: $('#customer-number-control'), + df: { + fieldtype: 'Link', + fieldname: 'customer_number', + options: 'Customer', + label: 'Customer Number', + reqd: 1, + placeholder: 'Search customer number...', + onchange: function() { + var val = customer_number_control.get_value(); + if (val) { + fetch_customer_details(val); + } else { + clear_customer_fields(); + } + } + }, + only_input: true, + }); + customer_number_control.refresh(); + // Style to match form + $('#customer-number-control .control-input').css('margin', '0'); + $('#customer-number-control .help-box').remove(); + + // Supplier (Driver) — Link to Supplier for driver name + supplier_control = frappe.ui.form.make_control({ + parent: $('#supplier-control'), + df: { + fieldtype: 'Link', + fieldname: 'supplier', + options: 'Customer', + label: 'Driver', + placeholder: 'Search driver...', + onchange: function() { + var val = supplier_control.get_value(); + if (val && val !== customer_number_control.get_value()) { + // Driver selected separately — don't override customer_number + } + } + }, + only_input: true, + }); + supplier_control.refresh(); + $('#supplier-control .control-input').css('margin', '0'); + $('#supplier-control .help-box').remove(); +} + +function fetch_customer_details(customer_name) { + frappe.call({ + method: 'frappe.client.get', + args: {doctype: 'Customer', name: customer_name}, + callback: function(r) { + if (r.message) { + var c = r.message; + // Auto-fill company name + if (c.customer_name && !$('#company_name').val()) { + $('#company_name').val(c.customer_name); + } + // Auto-fill custom CRM fields + if (c.contact_persons && !$('#contact_persons').val()) { + $('#contact_persons').val(c.contact_persons); + } + if (c.hours_of_operation && !$('#hours_of_operation').val()) { + $('#hours_of_operation').val(c.hours_of_operation); + } + if (c.legacy_notes && !$('#legacy_notes').val()) { + $('#legacy_notes').val(c.legacy_notes); + } + // Driver is independent — don't auto-populate from customer number + + // Fill contact fields from Supplier doc's native fields first + // ERPNext auto-populates these from the primary Contact/Address + if (c.customer_primary_contact) { + // Fetch the Contact doc for name/phone/email + frappe.call({ + method: 'frappe.client.get', + args: {doctype: 'Contact', name: c.customer_primary_contact}, + callback: function(cr) { + if (cr.message) { + var ct = cr.message; + var full_name = [ct.first_name, ct.last_name].filter(Boolean).join(' '); + if (full_name && !$('#contact_name').val()) { + $('#contact_name').val(full_name); + } + if (ct.email_id && !$('#contact_email').val()) { + $('#contact_email').val(ct.email_id); + } + if (ct.phone && !$('#contact_number').val()) { + $('#contact_number').val(ct.phone); + } + } + } + }); + } else { + // Fallback: use Supplier-level fields (mobile_no, email_id) + if (c.mobile_no && !$('#contact_number').val()) { + $('#contact_number').val(c.mobile_no); + } + if (c.email_id && !$('#contact_email').val()) { + $('#contact_email').val(c.email_id); + } + + // Last resort: search for any linked Contact + frappe.call({ + method: 'frappe.client.get_list', + args: { + doctype: 'Contact', + filters: [['Dynamic Link', 'link_name', '=', customer_name]], + fields: ['name', 'first_name', 'last_name', 'email_id', 'phone'], + limit_page_length: 1 + }, + callback: function(cr) { + if (cr.message && cr.message.length > 0) { + var c = cr.message[0]; + var full_name = [c.first_name, c.last_name].filter(Boolean).join(' '); + if (full_name && !$('#contact_name').val()) { + $('#contact_name').val(full_name); + } + if (c.email_id && !$('#contact_email').val()) { + $('#contact_email').val(c.email_id); + } + if (c.phone && !$('#contact_number').val()) { + $('#contact_number').val(c.phone); + } + } + } + }); + } + + // Fill address from Supplier doc's primary_address or linked Address + if (c.primary_address && !$('#address_line').val()) { + $('#address_line').val(c.primary_address); + } else if (c.customer_primary_address) { + frappe.call({ + method: 'frappe.client.get', + args: {doctype: 'Address', name: c.customer_primary_address}, + callback: function(ar) { + if (ar.message) { + var a = ar.message; + var addr = [a.address_line1, a.address_line2, a.city, a.state].filter(Boolean).join(', '); + if (addr && !$('#address_line').val()) { + $('#address_line').val(addr); + } + } + } + }); + } else { + // Fallback: search for any linked Address + frappe.call({ + method: 'frappe.client.get_list', + args: { + doctype: 'Address', + filters: [['Dynamic Link', 'link_name', '=', customer_name]], + fields: ['name', 'address_line1', 'city', 'state'], + limit_page_length: 1 + }, + callback: function(ar) { + if (ar.message && ar.message.length > 0) { + var a = ar.message[0]; + var addr = [a.address_line1, a.city, a.state].filter(Boolean).join(', '); + if (addr && !$('#address_line').val()) { + $('#address_line').val(addr); + } + } + } + }); + } + } + } + }); +} + +function clear_customer_fields() { + $('#company_name').val(''); + $('#contact_name').val(''); + $('#contact_number').val(''); + $('#contact_email').val(''); + $('#address_line').val(''); + if (supplier_control) supplier_control.set_value(''); +} + +// ── Form Helpers ────────────────────────────────────────────────────── + +function set_today_date() { + var today = new Date().toISOString().split('T')[0]; + $('#received_date').val(today); + $('#received_date').trigger('change'); +} + +function show_intake_form() { + $('#intake-form-container').show(); + $('#recent-pallets').hide(); + set_today_date(); + // Focus the customer number control + setTimeout(function() { + if (customer_number_control) { + customer_number_control.$input.focus(); + } + }, 200); +} + +function clear_form() { + $('#intake-form input[type="text"], #intake-form input[type="tel"], #intake-form input[type="email"], #intake-form input[type="number"], #intake-form input[type="date"], #intake-form textarea').val(''); + $('#legacy_notes').val(''); + $('#intake-form select').val(''); + $('#total_items').val('0'); + $('#num_labels').val('1'); + $('#amount').val('0'); + $('#needs_aor').prop('checked', false); + $('#needs_cod').prop('checked', false); + $('#btn-print-labels').prop('disabled', true); + $('#save-status').text(''); + $('#intake-form-container').data('pallet-name', ''); + if (customer_number_control) customer_number_control.set_value(''); + if (supplier_control) supplier_control.set_value(''); +} + +function save_pallet() { + var pallet_name = $('#intake-form-container').data('pallet-name'); + var is_new = !pallet_name; + + var data = { + doctype: 'Pallet', + received_date: $('#received_date').val(), + customer_number: customer_number_control ? customer_number_control.get_value() : '', + customer: customer_number_control ? customer_number_control.get_value() : '', + supplier: supplier_control ? supplier_control.get_value() : '', + company_name: $('#company_name').val(), + pickup: $('#pickup').val(), + data_status: $('#data_status').val(), + red_r2: $('#red_r2').val(), + barcode: $('#barcode').val(), + total_items: parseInt($('#total_items').val()) || 0, + num_labels: parseInt($('#num_labels').val()) || 1, + contact_name: $('#contact_name').val(), + contact_persons: $('#contact_persons').val(), + contact_number: $('#contact_number').val(), + contact_email: $('#contact_email').val(), + address_line: $('#address_line').val(), + hours_of_operation: $('#hours_of_operation').val(), + legacy_notes: $('#legacy_notes').val(), + weights: $('#weights').val(), + invoice_check_request: $('#invoice_check_request').val(), + amount: parseFloat($('#amount').val()) || 0, + paid_received: $('#paid_received').val(), + needs_aor: $('#needs_aor').is(':checked') ? 1 : 0, + needs_cod: $('#needs_cod').is(':checked') ? 1 : 0, + notes: $('#notes').val(), + status: 'Received' + }; + + if (!is_new) { + data.name = pallet_name; + } + + frappe.call({ + method: is_new ? 'frappe.client.insert' : 'frappe.client.update', + args: { doc: data }, + callback: function(r) { + if (r.message) { + var name = r.message.name; + $('#save-status').html(' Saved as Intake ' + name + ''); + $('#btn-print-labels').prop('disabled', false); + if (is_new) { + $('#intake-form-container').data('pallet-name', name); + } + } + }, + error: function(r) { + var msg = 'Unknown error'; + if (r && r._server_messages) { + try { + var msgs = JSON.parse(r._server_messages); + if (msgs && msgs.length) { + var errObj = JSON.parse(msgs[0]); + msg = errObj.message || msg; + } + } catch(e) {} + } + $('#save-status').html(' Error: ' + msg + ''); + } + }); +} + +function load_recent_pallets() { + frappe.call({ + method: 'frappe.client.get_list', + args: { + doctype: 'Pallet', + fields: ['name', 'pallet_number', 'status', 'customer_number', 'company_name', 'supplier', 'received_date', 'red_r2', 'total_items', 'weights', 'notes', 'needs_aor', 'needs_cod'], + limit_page_length: 20, + order_by: 'creation desc' + }, + callback: function(r) { + var tbody = $('#pallet-tbody'); + tbody.empty(); + if (!r.message || r.message.length === 0) { + tbody.append('No pallets yet'); + return; + } + r.message.forEach(function(p) { + var status_class = { + 'Received': 'info', + 'Sorting': 'warning', + 'Processing': 'primary', + 'Complete': 'success', + 'Shipped': 'default' + }[p.status] || 'default'; + + tbody.append( + '' + + '' + (p.status || 'Received') + '' + + '' + (p.customer_number || '') + '' + + '' + (p.supplier || '') + '' + + '' + (p.received_date || '') + '' + + '' + (p.red_r2 || '') + + (p.needs_aor ? ' AoR' : '') + + (p.needs_cod ? ' COD' : '') + + '' + + '' + (p.total_items || 0) + '' + + '' + (p.weights || '') + '' + + '' + + ' ' + + '' + + '' + + '' + ); + }); + } + }); +} + +function edit_pallet(name) { + frappe.call({ + method: 'frappe.client.get', + args: {doctype: 'Pallet', name: name}, + callback: function(r) { + if (r.message) { + var d = r.message; + $('#intake-form-container').show(); + $('#recent-pallets').hide(); + $('#intake-form-container').data('pallet-name', name); + $('#received_date').val(d.received_date || ''); + if (customer_number_control) customer_number_control.set_value(d.customer_number || ''); + if (supplier_control) supplier_control.set_value(d.supplier || ''); + $('#company_name').val(d.company_name || ''); + $('#pickup').val(d.pickup || ''); + $('#data_status').val(d.data_status || ''); + $('#red_r2').val(d.red_r2 || ''); + $('#barcode').val(d.barcode || ''); + $('#total_items').val(d.total_items || 0); + $('#num_labels').val(d.num_labels || 1); + $('#contact_name').val(d.contact_name || ''); + $('#contact_number').val(d.contact_number || ''); + $('#contact_email').val(d.contact_email || ''); + $('#address_line').val(d.address_line || ''); + $('#weights').val(d.weights || ''); + $('#invoice_check_request').val(d.invoice_check_request || ''); + $('#amount').val(d.amount || 0); + $('#paid_received').val(d.paid_received || ''); + $('#needs_aor').prop('checked', d.needs_aor === 1); + $('#needs_cod').prop('checked', d.needs_cod === 1); + $('#notes').val(d.notes || ''); + $('#received_date').trigger('change'); + $('#btn-print-labels').prop('disabled', false); + } + } + }); +} + +function print_labels() { + var pallet_name = $('#intake-form-container').data('pallet-name'); + if (!pallet_name) return; + print_pallet_labels(pallet_name); +} + +function print_pallet_labels(name) { + frappe.call({ + method: 'frappe.client.get', + args: {doctype: 'Pallet', name: name}, + callback: function(r) { + if (r.message) { + generate_zpl_label(r.message); + } + } + }); +} + +function generate_zpl_label(d) { + var label_count = d.num_labels || 1; + var date_str = d.received_date || ''; + var driver = d.supplier || ''; + var customer_num = d.customer_number || ''; + var red_r2 = d.red_r2 || ''; + var weight = d.weights || ''; + var pallet_num = d.pallet_number || d.name || ''; + var qr_url = window.location.origin + '/app/pallet/' + (d.name || pallet_num); + + var logo_url = window.location.origin + '/files/COR_html_952bb51d.png'; + + var labels_html = ''; + for (var i = 1; i <= label_count; i++) { + labels_html += '
'; + labels_html += '
WESTECH RECYCLERS
'; + labels_html += '
'; + labels_html += '
'; + labels_html += '
'; + labels_html += '
Pallet #: ' + pallet_num + '
'; + if (customer_num) { + labels_html += '
Customer #: ' + customer_num + '
'; + } + labels_html += '
Received: ' + date_str + '
'; + labels_html += '
Driver: ' + driver + '
'; + labels_html += '
Weight: ' + weight + '
'; + labels_html += '
Items: ' + (d.total_items || 0) + '
'; + labels_html += '
'; + labels_html += '
'; + labels_html += '
'; + if (red_r2) { + labels_html += '
' + red_r2 + '
'; + } + labels_html += ''; + labels_html += '
'; + } + + var existing = document.getElementById('label-preview-overlay'); + if (existing) existing.remove(); + + var overlay = document.createElement('div'); + overlay.id = 'label-preview-overlay'; + overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.6);z-index:9999;display:flex;align-items:center;justify-content:center;'; + + var modal = document.createElement('div'); + modal.style.cssText = 'background:#fff;border-radius:8px;padding:20px;max-height:90vh;overflow-y:auto;box-shadow:0 4px 20px rgba(0,0,0,0.3);max-width:95vw;'; + + var title = document.createElement('h3'); + title.textContent = 'Label Preview — Pallet ' + pallet_num + ' (' + label_count + ' label' + (label_count > 1 ? 's' : '') + ')'; + title.style.cssText = 'margin:0 0 15px 0;font-size:16pt;'; + + var btnGroup = document.createElement('div'); + btnGroup.style.cssText = 'margin-bottom:15px;display:flex;gap:10px;'; + + var printBtn = document.createElement('button'); + printBtn.className = 'btn btn-primary'; + printBtn.innerHTML = ' Print Labels'; + printBtn.onclick = function() { + var pw = window.open('', '_blank'); + pw.document.write('Labels — Pallet ' + pallet_num + ''); + pw.document.write('