From 5f2219fc0f1213d5fac71cbfe8508377733bb3bd Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 28 Jan 2026 00:04:21 +0000 Subject: [PATCH] Autosave: 20260128-000421 --- assets/vm-shot-2026-01-27T10-44-32-354Z.jpg | Bin 0 -> 29088 bytes core/__pycache__/apps.cpython-311.pyc | Bin 524 -> 1300 bytes core/__pycache__/forms.cpython-311.pyc | Bin 28254 -> 31190 bytes core/__pycache__/models.cpython-311.pyc | Bin 23169 -> 23593 bytes core/__pycache__/urls.cpython-311.pyc | Bin 6395 -> 7264 bytes core/__pycache__/views.cpython-311.pyc | Bin 46680 -> 48759 bytes core/apps.py | 19 ++ core/forms.py | 34 ++- ...ber_profile_license_back_image_and_more.py | 28 +++ ...icense_back_image_and_more.cpython-311.pyc | Bin 0 -> 1310 bytes core/models.py | 7 +- core/templates/core/register_choice.html | 73 ++++++ core/templates/core/register_driver.html | 222 ++++++++++++++++++ core/templates/core/register_shipper.html | 125 ++++++++++ core/urls.py | 14 +- core/views.py | 50 +++- 16 files changed, 563 insertions(+), 9 deletions(-) create mode 100644 assets/vm-shot-2026-01-27T10-44-32-354Z.jpg create mode 100644 core/migrations/0019_profile_car_plate_number_profile_license_back_image_and_more.py create mode 100644 core/migrations/__pycache__/0019_profile_car_plate_number_profile_license_back_image_and_more.cpython-311.pyc create mode 100644 core/templates/core/register_choice.html create mode 100644 core/templates/core/register_driver.html create mode 100644 core/templates/core/register_shipper.html diff --git a/assets/vm-shot-2026-01-27T10-44-32-354Z.jpg b/assets/vm-shot-2026-01-27T10-44-32-354Z.jpg new file mode 100644 index 0000000000000000000000000000000000000000..14ea974415e2207ce5717aa170d78b618481dcd7 GIT binary patch literal 29088 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 literal 0 HcmV?d00001 diff --git a/core/__pycache__/apps.cpython-311.pyc b/core/__pycache__/apps.cpython-311.pyc index 6f131d4873bc56e3763e4ed09960c6e3f34140e1..143a227f558987cb410a3af0d6565ad892e44920 100644 GIT binary patch literal 1300 zcmZuw&1(}u6rb7Mq)GY_+xXE|log>RAc-Ot6)E&XJ*Y*{(}FD1%rsry?8cc{n}!r~ zP$*ukP-u^yD&jxkpAeykWxh-$!gMeNqw`_+Y$dA@9)fkxrZ3CFh!O|v87YZGBm^zR6oE_ z31(NUBsHudns|k*6iq_Sp(wNDbJnd^KS!Suuk07-YN6s&=8D3iQ(g$9f5%}ijf@h6 z)+ZkjLAZIlR^?0x^8xWlnN^r4AD8-dpqd6#b=a8!09G(C0jz8(R)B>qt)Vrrt)gO~ z2)Z#=xN^X$GY=WBI6^qSH;`3j%)#uq0DDOOQL%xZ_N~EFZ{Y@h->(E4`$F+xB+oRU zPl{e^Q~j7nsDYt3eWh+J5zjm_U?s0dx{y3FJW^p%Mo7Y?*l^@}UW*LD+%-N5Q9{); z&7YTw>wbk5gVn&3L6Oy12`J^o4WB;~RZ?O_#cPpNtD;cdjM8G==hBAs^^3pnrob7Y zn}u7hUm~uUFZ6>H8{!&36MfB{-jTbT@8);sx0l0g?(NGrFZW-3$<7>RXW9sln&FwV z`wRPv`-{7^ootvpvwg1v8`Wv1dpBS5J;|Nb0tw`L?+x%YghWHO>d3b9I?sX~JNYr5D>+b!V=7&$@&t+)nvTI=~z(UoS&DLnVt+)0j3zCoX=tt=ZmtXFax!) zOuS{t?5D{(xs}<1_ZCZDVs7e6hR+~%lWm#w1d3RJEHJ?WWE4wI{>v=k)8NwJQp5|B z@Y7_z#hsFsn3tZfmsn6xTm*6zL>~``1y;xhWc}i>$<0qG%}KQ@5&&{Rjw$w@yq-nM Y@&g+aqtFKiOk#rMN08_jEK*=|0h_fyQvd(} diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index 25d2e3b3453a2a1110180643674d65b0965bed1c..9c79858b0d7073ea17e7096d32615c7e75f337f0 100644 GIT binary patch delta 3374 zcmb_edrVvB6~Ev03(UhnhJW zjH%?Y_DIU$dgk&+Cv%5MTbA9+K8uz5dcH%DE>UuwwLaNIfa7BfjD>`vK;ewxts z<2-w%*vvxK9Cpakl_%(qa{(|*tRo!FV^=J{j0naxVoNG77>kk~;P6eF;~Gz9(oD!m zwSsLPjhC?|-j0=wgcKD7%vuSUxlur7&CAy(GQ!7Z@W@{A$Xes^XyRF`DS(%W^;x%* zZ1w}|(>-xhh>rQC5z!NpeB%>TjBgr|d}1&xdi-=OIPQ@~y+dL=FDV@K`VKG4a(rIu z35|HiMNe>IbWo)B9QKj5FPFXnSy6^?7U3LAD{mrivi9-{{#C;K_roS9uIf2#C> zY4iDfrN|+h@QPU~6ifY_S+O)t8_s63`{iws1wEHjKGUgGZkJ7X-L6!c_saXet27@1 zF6O9J94+!Q-&Pzw(*`AHYs^%6O{;ACmTbc7wxG22%6+2J<_9iT+o06$lwHp&wFl6+ zI%cYv8CSM8$tJvR4=AlYa<5Nm6@ZJ?IF*_<*|BrKQZsax(%EdBxc#V6D6FD~#I5&Ta z^AmxbOmk~aag)TYg%iNX3-%97p^!+Q6NjYmIQ5Q8W5KR5I_e|KVUXzHHo?7kg=4P0 zo$MdQMt0hnTc<@OE`hA}g$J$GCGgNoDK_lAn*3b?2m5Mz=ov7H8^Vd*uN&wP@N^gf zyE>k+TM`5@xF;Bz7^lyoxER3&aGkvquh+W=uKf{QjF|4tGnQPBkO zuM=GIZ-Lk7_SP?O8r_qCy0;q82Vqv0I?{k!oF>d_>ns#>g8rgr)^HWFxViE=X4BZD zt%9Vpi?;F>onXAkueZ1gCAzX1>;7wfL)R}BG9cUNbiELMB-qt8Spkx(`^Xn@YOu#G|r+L z;d^k06{uy(X^fd|)1qRwUF*NrFW2?W*Yqnj{qjpM%hIGQ1r=#>f#aU#U*v&^{9zqAR%AcFSt+v5 zkvSqabj{ayEA`#-a|dKkQ1%FlCkSpXz6ZVCybs9{BBYR)iHISQKujcHQtU?=Acz2E ztvOa;o1Qoui6n~GK3~(J)O6gTYs%No??(6KD!TaZAQvERjD`flApv3GL6iZ42vFAM zFK9Ko2Aq|T15;9+7?!gv+fWoOv)$3~^xf!^y^ZM9Uk7Ygb(mac?^jprK7dZR5dE_H zw2|CmuQYy0F0rR}Tqf6}cXzy|Blp>VO1s&G)>ExN#@4}MMkRzx2$vD|Bb-L~5aAaH zQ3SP1FW}P*8*Q^#HvB%^LOsIi=*_nKJmi2GUupldzDA9%w)ID7v=^Zs!HLj-un*xg zfWJp??Y^7KmlF1UcVq2uQ2aZD&k=r$a2LUYfL{+PAp9OdW?#DdEvn(`$gBU)ukmRV z0VgxXnrtaj!(y;FFA0hGYJ`v38wZ^RGn}UICwlhJKza0U2eoPX7Z$mro`K}w0f_>gE15;DrHhv=nP)PoO&-E$@AVK3c>59i!-&iCAN&VBm> zR^EXjs@H2d`Eiwp0~%MiVJl>G=Z&KsvUKS@=i`MJ&Esg9qJyr%~fnqG2w1o zGC#-R0b7YG&Lv}utsr&TY+W)JjGbCC7u|4mRpGR)6qX;2ZU^XL(H&3uV!b*e&iw~O zyWCDJVjlZPl|fL6ndBZMWHG0s6pXRdpxERO)cb0Kfx709=);Ipf&u*M+@&6o^V*oD zxKj(g7(Fxz{n+l$#g4;mNw?&Xl(Gr!`8iBDa!w61c(ZcxSRX0VCdB}upD;l15IPA_ z88NN9;rs<(MZj0@jU`ve-QA7BP_sBn3B80tyyv!Bhsb;&LjoD);y&_+|Kbu`a)01q zm`zmu*65TrJ1I7X)sjX1Og0zTif7))uX8x=a~8g!;7h_RVUjRKs3p`9yo6VTX-xCi zSe3*s@|6J|lhr`b5tMagDzYRN;{)CeeMMm$r~Gz)jbq>Z`I|L!R4|J*mAP2nWYip$ z2a>Mi?aFKnH(jeqw6{E}P^MC9tH`}bpxuiJSHmbmc+HLnjR1_*ULFF?BE5ctDybxG zkjz4YBEPY!1=&Brg3>R5v)B+SgGGE2$_4>f1pz;YvfwmAODOR*=1GfCjdxqZNs1+y zFg@I-Qx2tk(mc+DE!t0V7Tr<0gI~hW9cKXKe>pMlI|j?XE3u#dX0-CSCt|{~NbetP C!v?qj diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 987996dd8f4cd5bd231dd964b99ee1198175cbe7..c579a654bd462406bdd95076f910eaa7758e91a0 100644 GIT binary patch delta 1720 zcma)5ZERCj81CEkBiqukwcWb5>sp9zY%7zYU;=Ec+kngsS75jgBIVNFlDe*A=Z>ih z8K@(oE{5+-NzQZ6 zdEWOt&wI{2=cRKndI54ynoL<5-X{GoMkcDx=6si@HD}1b=XC-8V$LZwkAOyViuZI2 zSwh*N?D0h-I?nQ*Zk@R}Wwxxe{;%9Ttwz*8r+U(AR6JJv!koX~tn!vQNsVabS^4ub za^>-iP{BfvaodQVSHgR`br#&GVtc4c;e#ss7swReCu4u8jQv5G1uBk^V@T8K3^_R# zg^D=3w3>~YkZVX2Djw1DT;AsjHx`H7TQy}KY_m>m7_c-)f?`Y(JsVh0tk2WfE$kKt zGNWlydThWvAFmUFU31~wdVzWTQK3)tJiWJjm&nkT|1E5jXYx-1?7(+yr=VS4U$_on zCmyta4kG#;>%fhN9j~lOS?06@VKNLv$S`G|CwFm|IW9LSu)rR23B=Ma7UxcFqZao% zr}y77Xq?`oB}qp`+!yyLmGud4L(#hH==hW9DJ zevW9heuG*+J5R(Ahg3$t5KS4Rz2R`=g|wW3(;jLE(wgf2taO#aJ*?Z$dcu*YsBZL< zJig{xfCOe$pV9xumnHF1^*)%uwKbcwe;|t~f}ikc&63K6TVY9xe8b`1@~;s|FfLEm zT-Cxg^qK5((x(87;fea=a1}Q;G{evMR>K>s6O??FV1`2~J0b=8MHUH1#1I31Caj8L ziwV@TnWYiIb?jJw8)oIL8%!BFcZeM$80UaKT{C{%=z~A;PUDw`+r($%m8Z_bzj&}| zJN$}MP0KP>^=V2ks&?Xv<_<98aPtmBK6ljt-fHfx&7lHJ1QVo@N26SVem+g<)fbhn zJCoNf1p6Yq_Paa!8jo+XXw86Ea*MKzw2t7Wd}Gu107m&@%imy7|MfAvuz3*9;FDWw zz=ZuKDdY$jNpO4~f>vHP^1&zV9>Ri1znd{1OQjG+ea$s9KfD9v`Ep umA;o@Ror0mgYe?6dsPw5I=i2=$BV@G{JwaIMg=) delta 1356 zcmaKrdu&rx9LMjk?QOSSJ4V}$KG%&9q_P(VF(G5CE@OXeV_jD2HiGPC_jb9ak9fO> zIs)4y$ix`TFCh?&OeAdxgDBSrK?x*aVhq_Pk{BBvGtPjCQI-$^HR}1@VrIa2lJmLe z{2t%?``vTyvC}a25fo)@HY>-*8SAjJwf2LeYfB9=1MX<7(}MOI@D`JghP+hfU$E!b z9485qfTF{>bIOt7Iqo={`O)Jra4c{!&G~Q|^BW~+23QuG`SFNK$wMlo|EW@v>G*${ zWm4%buE!-UV{}U{MvsAO<|OwnPV!_7tOPdmqsJ?GJGr0_jV0%?u=HC9Yu}e<0lIOo z>o|03PrDlcw&1YmOX$Uuf(r$U4g0+w@Zq@kRSfxh4by-}e77{dY#+b~?hic6k27rv zuLY*rt2r)bN{d5s(5Q~Ejk=RCh8N0L@UO9@qWx4pWr2fuaMh^!F!?66Kybgov74=f zCe_a#Ig_aNr&-b$tNnJezaoT1wNH*$lkg$DyZRhV;U|@~Fp0M+--HPqu6mq5%>v)k zOa8Pf>6v0XwSizFga|E!m$9+>SNIs$*R;cKe7z>%`H-2@bVebyj3OrfK~lR=)6T<$ z=6LEyOV=qf>s6ZdDpidPV+=XtkQmRI(}S^?@{+2{nVGqq#%Nws@4^|5ivzKgnh2|@ zm=c%ucFtO;;&;i>xf`I{_l2KyVf!&#hf=n$^bE3OmfFcex|O)~0A!jpur2$vcD zUH%m^60+L9&}9Q$!Dno4ZF}P^Ko;AY-h~ux{gC|1<^95PoLJ2}*j~kgO^( zMV8b*@h!n&T_7jnYlPb?$(kh`!%4RrZxpUWZ)*uYVfEUJBXW8`Nu-jB z7_Ux>3Hdf2ZMjr}l3 z@~IDs#kr{8>Y|beCe89(7k~?UyFQ1LxUxI2f&Mv_{;2$Y)lXeNE4>dra}9Yb2z0N1 pE2vAPq`|mcuddO?yKAAc0xEBFk77^kjraoD?<_huYS(*O;BQ!7WZD1# diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 0394ab04b72b0b11f5bf671edc02b9b10c15697c..c89533699b57c7e0c0570376523122a28063934d 100644 GIT binary patch delta 1796 zcmZ{k%TF6e7{IX^$7>Ss3vA=%;Uorw3Na*@+BA^zemEH1)ZyU)UYISEZ#TMP%&8x1?6*L7B%`u)J=F8cK_oN@<=Bq2l0;+v*aFm&#azq}(KB@`zx` z3g6zSsS+v$ufPjcLiI__k*TQYYckmoYN_cXrj45A!tIliBLgwWyfp4m<1R7m)Nl!Y zq3)#q$VePAFP#8&8i?bdPKnT{cRBsh_(w6>ZS$2nOVu>l?L8PX{|bEulSvY9EZrv$ zHXD{`ahc!)4Ob|>AlRbeD#Z-JRt>Wh*RHBE#hhN{^C#w`VzNmx**Gvvw+ZV{iW)cI zIQOdGE{o5lTwauexkV|PCBGLoJ(aplZC_=Af-G%N$9m<^%<0eEPX>eQ^oJ6UX=l4E zot3n1FT~Y+E_h)lthJ(?S|O`#yRRz`rPX{#cDXBf;k@PwVm>XcY?sh|TsCvanN0p4 z-JE~bA4)#GRrz(3^@=ry;4juSvur1CLw3M9+kB8G;l-`oe0nvtCZ{$eaZ|3Q)f)O$ zs}=KddVV>TP0RD*3jEy`4aqIE*s2w?a%MqV5!sUuXv#|7k+iUt%H*>w8=`hQ%-dhz zoFE~+Rk?4?u*DItjvK7T?*X^lx98YPe3mS1A`nnO0E2*99EV>zf`&N!&JpxePrX%S zvJjKs7hkR(cOcNNfOZVp)l#im1`o=;4OT6-X(qDpg#@m?k0K)oL=_OlAgbCm!2xeO zy=JEtdti@q&|Im-4RGHXF*j;)3q;N?bE_72z>4y4;5{wwF|d79?XSPwIZh%FQ9uNP zh}vt=>U}WfuC(+s7%rD!QgaQ&6B-AJ~9$&8H z*$-i7-SHp-Z3<|^piLcRLhS!rj4@;U--bT zOzNGQjzxU04@I9LFr$DO3})0RrcCR~f4ui3Q$B(g7tcLoFbkVpUM|gG4#r4jo`C?@ zT;3g#!2)Z$S6it2qWM@tAgq8e24VF%t1s%y-aSm3wS zOJIw^HhkswHhse2edFb&tS+qM+IG}AjzC-iaSY;Ww~^f}qjp((84W>;C%_Fe7=d9= zJr`y07%q^?D1#XMoWK}^arlj=ekac0slH-mA%gkHIp2N8cPo4^=6lh|-%f9W>65yC z=WrPNyUzUsXZ``jKZN~5XiPvrRDg(qs7^6`hUt4%`&-x@I(K)TxjPm2BkX=OiUy_; zNGc$SK~haIeOB*Yb7;Z7j&onnnXgCj^Bee-^;o9ym1Z}R)R@8|vcW?uU? z{NY&j{i>>R8^3PtE@yAnZdCj12j$0|Ba#DhRphy=IiPv8M$N1FH2iop#47$ zI=E32%s6s&pBHsni@Nw!{oWh!%}r-u89nVtOW@TF_IsvzcXGC6qi#hP#BH}cKCk?z-(^ZMLu_C^L*9<%(K+ZjDOdnYxwG>@|(Ysqo)$G*oE z6r|1yQ70Z9f)vqA{9>JoJ?dD<8r42k+AeqCVw*5*oKl0w9Q2!n`uN~EVTRn{k%Cs@c*2pbS) z5H|ZoJU})S#dSv1XUSEsBA=54M9B*dF@!;~?e)uXg!3X9LP!W0Mz~-#=pI2Bm5LAA zS!id6;&e1kK{G&OpqXQ+TqGBKs(cCID{_;=IKpMJ?o(Hi2w#^vDO+(CI7+`9qL45k z!60Eypz@+n(w3UHovii56aL)8 z29RmR>0U(RCyC@0#eE0quGpXaGtybIrv&A5_Tq2iozfx45C%!D8kFM*=gAokLkJ0y SS3By41*}$BAN>;lD}4fVy;n8> diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 782558d8c2cef7f868187eb18e93583866ba5552..ad9397a45c843d061333a1d30ab89c60d78cc0a4 100644 GIT binary patch delta 8646 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 MXgK;|k{SB`4-du^WdHyG delta 7296 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 diff --git a/core/apps.py b/core/apps.py index 8115ae6..fcb1d96 100644 --- a/core/apps.py +++ b/core/apps.py @@ -1,6 +1,25 @@ from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ class CoreConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'core' + verbose_name = _('Masar Express Management') + default = True + + def ready(self): + from django.contrib.auth.models import Permission + + # Monkey-patch Permission.__str__ to show a VERY short name + # Standard was: "app_label | model | name" (e.g. core | country | Can add country) + # Previous fix: "Country | Can add country" + # New fix: "add Country", "change Country" (strips "Can " prefix) + + def short_str(self): + name = str(self.name) + if name.startswith("Can "): + return name[4:] + return name + + Permission.__str__ = short_str \ No newline at end of file diff --git a/core/forms.py b/core/forms.py index 86188ba..a4477c8 100644 --- a/core/forms.py +++ b/core/forms.py @@ -96,14 +96,44 @@ class UserRegistrationForm(forms.ModelForm): user.save() # Profile is created by signal, so we update it profile, created = Profile.objects.get_or_create(user=user) - profile.role = self.cleaned_data['role'] + # Handle role if it exists in cleaned_data (it might be excluded in subclasses) + if 'role' in self.cleaned_data: + profile.role = self.cleaned_data['role'] profile.phone_number = self.cleaned_data['phone_number'] profile.country = self.cleaned_data['country'] profile.governate = self.cleaned_data['governate'] profile.city = self.cleaned_data['city'] + + # Save extra driver fields if they exist + if 'profile_picture' in self.cleaned_data and self.cleaned_data['profile_picture']: + profile.profile_picture = self.cleaned_data['profile_picture'] + if 'license_front_image' in self.cleaned_data and self.cleaned_data['license_front_image']: + profile.license_front_image = self.cleaned_data['license_front_image'] + if 'license_back_image' in self.cleaned_data and self.cleaned_data['license_back_image']: + profile.license_back_image = self.cleaned_data['license_back_image'] + if 'car_plate_number' in self.cleaned_data: + profile.car_plate_number = self.cleaned_data['car_plate_number'] + profile.save() return user +class ShipperRegistrationForm(UserRegistrationForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['role'].widget = forms.HiddenInput() + self.fields['role'].initial = 'shipper' + +class DriverRegistrationForm(UserRegistrationForm): + profile_picture = forms.ImageField(label=_("Profile Picture (Webcam/Upload)"), required=True, widget=forms.FileInput(attrs={'class': 'form-control', 'capture': 'user', 'accept': 'image/*'})) + license_front_image = forms.ImageField(label=_("License Front Image"), required=True, widget=forms.FileInput(attrs={'class': 'form-control', 'accept': 'image/*'})) + license_back_image = forms.ImageField(label=_("License Back Image"), required=True, widget=forms.FileInput(attrs={'class': 'form-control', 'accept': 'image/*'})) + car_plate_number = forms.CharField(label=_("Car Plate Number"), max_length=20, required=True, widget=forms.TextInput(attrs={'class': 'form-control'})) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['role'].widget = forms.HiddenInput() + self.fields['role'].initial = 'car_owner' + class UserProfileForm(forms.ModelForm): first_name = forms.CharField(label=_("First Name"), max_length=150, widget=forms.TextInput(attrs={'class': 'form-control'})) last_name = forms.CharField(label=_("Last Name"), max_length=150, widget=forms.TextInput(attrs={'class': 'form-control'})) @@ -347,4 +377,4 @@ class DriverRatingForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Reverse choices for CSS star rating logic (5 to 1) to ensure left-to-right filling - self.fields['rating'].choices = [(i, str(i)) for i in range(5, 0, -1)] \ No newline at end of file + self.fields['rating'].choices = [(i, str(i)) for i in range(5, 0, -1)] diff --git a/core/migrations/0019_profile_car_plate_number_profile_license_back_image_and_more.py b/core/migrations/0019_profile_car_plate_number_profile_license_back_image_and_more.py new file mode 100644 index 0000000..0944535 --- /dev/null +++ b/core/migrations/0019_profile_car_plate_number_profile_license_back_image_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.7 on 2026-01-27 23:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0018_alter_otpverification_purpose'), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='car_plate_number', + field=models.CharField(blank=True, max_length=20, verbose_name='Car Plate Number'), + ), + migrations.AddField( + model_name='profile', + name='license_back_image', + field=models.ImageField(blank=True, null=True, upload_to='licenses/', verbose_name='License Back Image'), + ), + migrations.AddField( + model_name='profile', + name='license_front_image', + field=models.ImageField(blank=True, null=True, upload_to='licenses/', verbose_name='License Front Image'), + ), + ] diff --git a/core/migrations/__pycache__/0019_profile_car_plate_number_profile_license_back_image_and_more.cpython-311.pyc b/core/migrations/__pycache__/0019_profile_car_plate_number_profile_license_back_image_and_more.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac07d529f3a21d8e1aabfdfea69fdd5fbd1c3274 GIT binary patch literal 1310 zcmah{%}>-o6rX- zBRBp7#K^&;N6(&?WKGCiJ#jHh;Ka$9ZVR#ynYOR*W8QDxd%yWSFrWdpe$B7i8xjD& zxsk10svJ%+WfLHP1P8c6O>o7UC;$;W1xWk|kc5R6%k8Z#rhPrJY7&xPfog7_2dg60 zT)Rok$o9REDz1;P6Iy9v@++ps;UA`K0t{*b0yPl{O`#@<0L!hcD0VdB9;KDf0FaDw zNZHAsEn%l{);@=#CMbn}P-LW`D?7z4nYF^c-ntZL;6j|i%W#@fO+{DPkV;g2nN5d{ zO16B0X=QTq-UDbl5hl=&g7=u%4ckg42!ogeeu!y4Ab!JkFfCaofq`R27<#c=$7ErD zm=(WPnl?#!p8LyliN7k*T-`CfWk!g(0v+r%qa|8o=ye7NJ=4W(iXrin+Qfe8RXuf z46i|aFG>N2GL#wa?7_@cHClj4MG#UALRMkyV5S!#d>5Mzuaa8`2iQZ{vuqp^ej91w zF+wxEdcql{>hzLH5}RsCg{kfbIK7`=z#-cRjw55qcd-%IV=sygyn?Nm)opz6$#NK& z7B)Cf#_7E_7-J7%N(t;| +
+
+
+

{% trans "Welcome to masarX" %}

+

{% trans "Choose how you want to join us today." %}

+
+
+ +
+ +
+
+
+
+ +
+

{% trans "I am a Shipper" %}

+

{% trans "I want to send parcels and track my shipments easily." %}

+ {% trans "Register as Shipper" %} +
+
+
+ + +
+
+
+
+ +
+

{% trans "I am a Car Owner" %}

+

{% trans "I want to deliver parcels and earn money on my own schedule." %}

+ {% trans "Register as Car Owner" %} +
+
+
+
+ +
+

{% trans "Already have an account?" %} {% trans "Login here" %}

+
+
+ + + +{% endblock %} diff --git a/core/templates/core/register_driver.html b/core/templates/core/register_driver.html new file mode 100644 index 0000000..1120f0a --- /dev/null +++ b/core/templates/core/register_driver.html @@ -0,0 +1,222 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} + +{% block title %}{% trans "Register as Car Owner" %} | masarX{% endblock %} + +{% block content %} +
+
+
+
+ + + +
+
+

{% trans "Car Owner Registration" %}

+
+ {% csrf_token %} +
+ {% for field in form %} + {% if field.is_hidden %} + {{ field }} + {% else %} +
+ + + {% if field.name == 'profile_picture' %} +
+ {{ field }} + +
+ {% else %} + {{ field }} + {% endif %} + + {% if field.help_text %} +
{{ field.help_text }}
+ {% endif %} + {% if field.errors %} +
{{ field.errors }}
+ {% endif %} +
+ {% endif %} + {% endfor %} +
+ +
+ + {% trans "Please provide clear photos of your license (front and back) and car plate number for verification." %} +
+ + +
+
+
+
+
+
+
+ + + + + + + +{% endblock %} diff --git a/core/templates/core/register_shipper.html b/core/templates/core/register_shipper.html new file mode 100644 index 0000000..9eea66d --- /dev/null +++ b/core/templates/core/register_shipper.html @@ -0,0 +1,125 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans "Register as Shipper" %} | masarX{% endblock %} + +{% block content %} +
+
+
+
+ + + +
+
+

{% trans "Shipper Registration" %}

+
+ {% csrf_token %} +
+ {% for field in form %} + {% if field.is_hidden %} + {{ field }} + {% else %} +
+ + {{ field }} + {% if field.help_text %} +
{{ field.help_text }}
+ {% endif %} + {% if field.errors %} +
{{ field.errors }}
+ {% endif %} +
+ {% endif %} + {% endfor %} +
+ +
+
+
+
+
+
+
+ + + + +{% endblock %} diff --git a/core/urls.py b/core/urls.py index d6e84f3..685628e 100644 --- a/core/urls.py +++ b/core/urls.py @@ -7,7 +7,11 @@ urlpatterns = [ path('', views.index, name='index'), path('login/', auth_views.LoginView.as_view(template_name='core/login.html'), name='login'), path('logout/', auth_views.LogoutView.as_view(next_page='/'), name='logout'), + + # Registration Flow path('register/', views.register, name='register'), + path('register/shipper/', views.register_shipper, name='register_shipper'), + path('register/driver/', views.register_driver, name='register_driver'), path('register/verify/', views.verify_registration, name='verify_registration'), # Password Reset URLs @@ -66,10 +70,18 @@ urlpatterns = [ path('login/request-otp/', views.request_login_otp, name='request_login_otp'), path('login/verify-otp/', views.verify_login_otp, name='verify_login_otp'), - # API Endpoints + # API Endpoints (Standard) path('api/auth/token/', api_views.CustomAuthToken.as_view(), name='api_token_auth'), path('api/parcels/', api_views.ParcelListCreateView.as_view(), name='api_parcel_list'), path('api/parcels//', api_views.ParcelDetailView.as_view(), name='api_parcel_detail'), path('api/track//', api_views.PublicParcelTrackView.as_view(), name='api_track_parcel'), path('api/profile/', api_views.UserProfileView.as_view(), name='api_user_profile'), + + # Aliases for mobile app compatibility (API v1) + path('api/shipments/', api_views.ParcelListCreateView.as_view(), name='api_shipment_list'), + path('api/shipments//', api_views.ParcelDetailView.as_view(), name='api_shipment_detail'), + + # Root-level Aliases (for apps hardcoded to /shipments/) + path('shipments/', api_views.ParcelListCreateView.as_view(), name='root_shipment_list'), + path('shipments//', api_views.ParcelDetailView.as_view(), name='root_shipment_detail'), ] \ No newline at end of file diff --git a/core/views.py b/core/views.py index 8229611..ce6cfdb 100644 --- a/core/views.py +++ b/core/views.py @@ -4,7 +4,7 @@ from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from .models import Parcel, Profile, Country, Governate, City, OTPVerification, PlatformProfile, Testimonial, DriverRating -from .forms import UserRegistrationForm, ParcelForm, ContactForm, UserProfileForm, DriverRatingForm +from .forms import UserRegistrationForm, ParcelForm, ContactForm, UserProfileForm, DriverRatingForm, ShipperRegistrationForm, DriverRegistrationForm from django.utils.translation import gettext_lazy as _ from django.utils.translation import get_language from django.contrib import messages @@ -77,8 +77,11 @@ def track_parcel(request): }) def register(request): + return render(request, 'core/register_choice.html') + +def register_shipper(request): if request.method == 'POST': - form = UserRegistrationForm(request.POST) + form = ShipperRegistrationForm(request.POST) if form.is_valid(): # Save user but inactive user = form.save(commit=True) @@ -110,8 +113,45 @@ def register(request): request.session['registration_user_id'] = user.id return redirect('verify_registration') else: - form = UserRegistrationForm() - return render(request, 'core/register.html', {'form': form}) + form = ShipperRegistrationForm() + return render(request, 'core/register_shipper.html', {'form': form}) + +def register_driver(request): + if request.method == 'POST': + form = DriverRegistrationForm(request.POST, request.FILES) + if form.is_valid(): + # Save user but inactive + user = form.save(commit=True) + user.is_active = False + user.save() + + # Generate OTP + code = ''.join(random.choices(string.digits, k=6)) + OTPVerification.objects.create(user=user, code=code, purpose='registration') + + # Send OTP + method = form.cleaned_data.get('verification_method', 'email') + otp_msg = _("Your Masar Verification Code is %(code)s") % {'code': code} + + if method == 'whatsapp': + phone = user.profile.phone_number + send_whatsapp_message(phone, otp_msg) + messages.info(request, _("Verification code sent to WhatsApp.")) + else: + send_html_email( + subject=_('Verification Code'), + message=otp_msg, + recipient_list=[user.email], + title=_('Welcome to Masar!'), + request=request + ) + messages.info(request, _("Verification code sent to email.")) + + request.session['registration_user_id'] = user.id + return redirect('verify_registration') + else: + form = DriverRegistrationForm() + return render(request, 'core/register_driver.html', {'form': form}) def verify_registration(request): if 'registration_user_id' not in request.session: @@ -888,4 +928,4 @@ def cancel_parcel(request, parcel_id): parcel.save() messages.success(request, _("Shipment cancelled successfully.")) - return redirect('dashboard') \ No newline at end of file + return redirect('dashboard')