Ë
    >^¡j>4  ã                  óT  — d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	 ddl
mZmZ ddlmZ dd	lmZmZmZmZ dd
lmZmZmZmZmZ ddlmZ ddlmZmZ ddlm Z  ddl!m"Z" ddl#m$Z$m%Z% ddl&m'Z'  e	«       Z( ejR                  e*«      Z+ejX                  jZ                  ejX                  j\                  ejX                  j^                  ejX                  j`                  ejX                  jb                  ejX                  jd                  fZ3dd„Z4dd„Z5ddœ	 	 	 	 	 dd„Z6dd„Z7dd„Z8ddd„Z9y)zE
Bidding Rate Distribution and Sequential/Broadcast Dispatch Engine.
é    )ÚannotationsN)ÚDecimal)Úsettings)Úget_user_model)ÚmodelsÚtransaction)Útimezone)ÚPlatformSettingsÚTransporterProfileÚUserRoleÚVehicle)ÚBidÚRateRequestÚShipmentÚTripÚZone)Úvehicle_matches_required_type)Únormalize_country_codeÚ!transporter_load_search_radius_km)Úcountry_code_for_point)Únotify_users)Úget_latest_device_positionÚget_latest_positions_map)Úrecord_trip_statusc                ó¶  — dd l }d}|j                  || z
  «      }|j                  ||z
  «      }|j                  |dz  «      dz  |j                  |j                  | «      «      |j                  |j                  |«      «      z  |j                  |dz  «      dz  z  z   }d|j	                  |j                  |«      |j                  d|z
  «      «      z  }	||	z  S )Nr   g     ã¸@é   é   )ÚmathÚradiansÚsinÚcosÚatan2Úsqrt)
Úlat1Úlon1Úlat2Úlon2r   Ú	radius_kmÚdlatÚdlonÚaÚcs
             ú0/var/www/html/truck-me/core/rate_distribution.pyÚ_haversine_kmr.   '   sË   € Ûà€IØ�<‰<˜˜t™Ó$€DØ�<‰<˜˜t™Ó$€Dà�‰�˜‘Ó˜aÑØ
�(‰(�4—<‘< Ó%Ó
&¨¯©°$·,±,¸tÓ2DÓ)EÑ
EÈÏÉÐQUÐXYÑQYÓHZÐ^_ÑH_Ñ
_ñ	`ð ð 	
ˆD�J‰J�t—y‘y “| T§Y¡Y¨q°1©uÓ%5Ó6Ñ6€AØ�q‰=Ðó    c           
     ó–  — | j                   �| j                  €g S 	 t        | j                   «      }t        | j                  «      }t        | j                  xs t        ||«      xs d«      }	 t        «       }t        t        j                  j                  t        ¬«      j                  dd¬«      «      t        t        j                  j                  t        d¬«      j                  d	d¬«      «      z  }g }t         j                  j                  dt"        j$                  j&                  d¬
«      j)                  |¬«      j+                  dd«      }|D �]ˆ  }|j,                  }	t/        |j0                  xs d«      j3                  «       }
|
sŒ:|j5                  |
«      }|s	 t7        |
«      }|sŒ\	 t        |d   «      }t        |d   «      }t        ||«      }|sŒˆ|j:                  r| j:                  r||k7  r,Œ¦|j<                  r| j<                  s| j:                  sŒË||k7  rŒÑt?        |«      \  }}tA        ||||«      }||kD  rŒótB        j                  j                  tE        jF                  |	¬«      tE        jF                  |	¬«      z  dd¬«      }d}|D ]  }tI        || jJ                  «      sŒ|} n |s�Œg|jM                  |	||tO        |d«      ||dœ«       �Œ‹ |jQ                  d„ ¬«       |S # t        t        f$ r g cY S w xY w# t        $ r i }Y �Œ¢w xY w# t        $ r d}Y �Œw xY w# t        t        t8        f$ r Y �Œów xY w)z{
    Find all available, verified drivers compatible with this shipment,
    ranked by ascending distance from pickup.
    NÚ )Ú
status__inÚtransporter_idT©ÚflatF)r2   Úassigned_driver__isnullÚassigned_driver_id)Úuser__is_activeÚuser__role__roleÚdocuments_verified)Úuser_id__inÚuserÚ
user__roleÚlatitudeÚ	longitude)Úowner)Úassigned_driver)Úis_verifiedÚ	is_activer   )ÚdriverÚprofileÚvehicleÚdistance_kmÚlatÚlonc                ó   — | d   S )NrG   © )Úxs    r-   ú<lambda>z4find_eligible_drivers_for_shipment.<locals>.<lambda>¢   s   € ¨1¨]Ñ+;€ r/   )Úkey))Ú
pickup_latÚ
pickup_lonÚfloatÚ	TypeErrorÚ
ValueErrorr   Úpickup_country_coder   r   Ú	ExceptionÚsetr   ÚobjectsÚfilterÚACTIVE_TRIP_STATUSESÚvalues_listr   r   ÚRoleÚTRANSPORTERÚexcludeÚselect_relatedr<   ÚstrÚtc_idÚstripÚgetr   ÚKeyErrorÚlocalÚcountry_to_countryr   r.   r   r   ÚQr   Úvehicle_type_requiredÚappendÚroundÚsort)ÚshipmentrO   rP   Úshipment_countryÚpositions_mapÚbusy_driver_idsÚeligible_candidatesÚprofilesrE   r<   r`   ÚposÚ
driver_latÚ
driver_lonÚdriver_countryr(   Ú_Údist_kmÚuser_vehiclesÚmatching_vehicleÚvs                        r-   Ú"find_eligible_drivers_for_shipmentrz   5   s]  € ð
 ×ÑÐ" h×&9Ñ&9Ð&AØˆ	ðÜ˜8×.Ñ.Ó/ˆ
Ü˜8×.Ñ.Ó/ˆ
ô .Ø×$Ñ$Ò\Ô(>¸zÈ:Ó(VÒ\ÐZ\óÐðÜ0Ó2ˆô Ü�‰×ÑÔ';ÐÓ<ß	‰Ð%¨DˆÓ	1óô 	Ü�‰×ÑÔ';ÐUZÐÓ[ß	‰Ð)°ˆÓ	5ó	ñ€Oð Ðô 	×"Ñ"×)Ñ)Ø Ü%Ÿ]™]×6Ñ6Ø#ð 	*ó 	
÷
 
‰˜_ˆÓ	-ß	‰˜ Ó	-ð ð ó ?ˆØ�|‰|ˆÜ�W—]‘]Ò( bÓ)×0Ñ0Ó2ˆÙØà×Ñ Ó&ˆÙðÜ0°Ó7�ñ Øð	Ü˜s :™Ó/ˆJÜ˜s ;Ñ/Ó0ˆJô 0°
¸JÓGˆÙØð �=Š=Ø—>’> ^Ð7GÒ%GØØ×'Ò'Ø×.Ò.°x·~²~ØØÐ!1Ò1Øô 9¸ÓH‰ˆ	�1Ü 
¨J¸
ÀJÓOˆØ�YÒØô  Ÿ™×.Ñ.Ü�H‰H˜4Ô ¤6§8¡8¸DÔ#AÑAØØð /ó 
ˆð
  ÐØò 	ˆAÜ,¨Q°×0NÑ0NÕOØ#$Ð Ùð	ñ
  Ùà×"Ñ"ØØØ'Ü  ¨!Ó,ØØñ$
ö 	ðq?ðB ×ÑÑ!;ÐÔ<ØÐøôG ”zÐ"ò ØŠ	ðûô ò Ø‹ðûôD ò Ø“ðûô œ:¤xÐ0ò 	Úð	úsG   œ*K5 Á.
L Æ"LÆ1L0Ë5L	ÌL	ÌLÌLÌL-Ì,L-Ì0MÍM©Úbatch_numberc               óÔ  — | j                   t        j                  j                  k7  r-t        j                  d| j                  | j                   «       g S t        j                  «       }t        dt        t        |dd«      xs d«      «      }t        j                  j                  | ¬«      }t        |j!                  dd¬«      «      }|€0|j#                  t%        j&                  d	«      «      d
   }|xs ddz   }t)        | «      }|D �cg c]  }|d   j*                  |vsŒ|‘Œ }	}|	s"t        j                  d| j                  «       g S |	d| }
g }t-        j.                  «       5  |
D ]‰  }t        j                  j1                  | |d   |t        j                  j2                  t5        t7        |d   «      «      | j8                  | j:                  xs ddœ¬«      \  }}|sŒy|j=                  |«       Œ‹ 	 ddd«       |D ]í  }	 t?        |j@                  gdt7        |j*                  «      t7        | j*                  «      | jB                  xs t7        | j*                  «      t7        |jD                  xs d«      |j:                  t7        |jF                  «      | jH                  | jJ                  | jL                  dœ	dd| jL                  › d|jD                  xs d› d|j:                  › d�¬«       Œï t        j                  d|tS        |«      | j                  «       |S c c}w # 1 sw Y   �Œ.xY w# tN        $ r/ t        jQ                  d|j@                  |j*                  «       Y �Œfw xY w)z…
    Dispatch rate requests to the next batch of eligible drivers based on
    PlatformSettings.bidding_rate_distribution_count.
    z8Cannot dispatch rate requests: shipment #%s status is %sr   Úbidding_rate_distribution_count©rk   Ú	driver_idTr4   Nr|   Úbatch_number__maxr   rD   z1No remaining uncontacted drivers for shipment #%srG   ÚUSD)r|   ÚstatusrG   Úoffered_priceÚcurrency)rk   rD   ÚdefaultsÚRATE_REQUESTr1   )	Úrate_request_idÚshipment_idÚ	unique_idr„   r…   r|   Úpickup_addressÚdelivery_addressÚ
cargo_typezNew Load Rate RequestzA new load (z") is requested for you with offer Ú ú.©ÚtitleÚbodyz.Failed to notify driver %s for rate request %sz9Dispatched batch #%s of %s rate requests for shipment #%s)*rƒ   r   ÚStatusÚ	PUBLISHEDÚloggerÚinfoÚpkr
   ÚloadÚmaxÚintÚgetattrr   rW   rX   rV   rZ   Ú	aggregater   ÚMaxrz   Úidr   ÚatomicÚget_or_createÚPENDINGr   r_   Úsuggested_pricer…   rh   r   r€   rŠ   r„   r|   r‹   rŒ   r�   rU   Ú	exceptionÚlen)rk   r|   ÚpsÚ
batch_sizeÚexisting_requestsÚcontacted_driver_idsÚ	max_batchÚeligibler,   ÚuncontactedÚto_dispatchÚcreated_requestsÚitemÚrrÚcreateds                  r-   Ú#dispatch_rate_requests_for_shipmentr±   ¦   s)  € ð ‡�œ(Ÿ/™/×3Ñ3Ò3Ü�‰ÐNÐPX×P[ÑP[Ð]e×]lÑ]lÔmØˆ	ä	×	Ñ	Ó	 €BÜ�QœœG BÐ(IÈ1ÓMÒRÐQRÓSÓT€Jä#×+Ñ+×2Ñ2¸HÐ2ÓEÐÜÐ0×<Ñ<¸[ÈtÐ<ÓTÓUÐàÐØ%×/Ñ/´·
±
¸>Ó0JÓKÐL_Ñ`ˆ	Ø!š Q¨!Ñ+ˆä1°(Ó;€HØ&ÖU˜¨!¨H©+¯.©.Ð@TÒ*T’1ÐU€KÐUáÜ�‰ÐGÈÏÉÔUØˆ	à˜k˜zÐ*€KØ*,Ðä	×	Ñ	Ó	ñ ,Øò 	,ˆDÜ%×-Ñ-×;Ñ;Ø!Ø˜H‘~à$0Ü)×0Ñ0×8Ñ8Ü#*¬3¨t°MÑ/BÓ+CÓ#DØ%-×%=Ñ%=Ø (× 1Ñ 1Ò :°Uñð <ó 
‰KˆB�ò Ø ×'Ñ'¨Õ+ñ	,÷,ð  ò dˆð	dÜØ—‘�Øä'*¨2¯5©5£zÜ#& x§{¡{Ó#3Ø!)×!3Ñ!3Ò!G´s¸8¿;¹;Ó7GÜ%(¨×)9Ñ)9Ò)?¸RÓ%@Ø "§¡Ü$'¨¯©Ó$8Ø&.×&=Ñ&=Ø(0×(AÑ(AØ"*×"5Ñ"5ñ
ð .Ø# H×$7Ñ$7Ð#8Ð8ZÐ[]×[kÑ[kÒ[qÐoqÐZrÐrsÐtv×tÑtð  tAð  ABð  Cöðdô, ‡K�KØCØÜÐÓØ�‰ô	ð Ðùòk V÷,ñ ,ûôF ò 	dÜ×ÑÐMÈrÏ|É|Ð]_×]bÑ]b×cð	dús2   Ä
LÄ!LÅ&A;L"Ç"L"ÈC*L/Ì"L,Ì/4M'Í&M'c                ó„  — | j                   t        j                  j                  k7  rg S t        j
                  j                  | t        j                  j                  ¬«      j                  «       rg S t        j
                  j                  | ¬«      j                  t        j                  d«      «      d   }|€t        | «      S t        j
                  j                  | |t        j                  j                  ¬«      j                  «       }|s1t        j                  d|| j                   «       t        | |dz   ¬«      S g S )	z‹
    Check if the current batch is fully exhausted (all rejected/cancelled/expired).
    If so, automatically dispatch the next batch.
    ©rk   rƒ   r   r|   r�   )rk   r|   rƒ   zVBatch #%s for shipment #%s fully resolved with no acceptance; advancing to next batch.r   r{   )rƒ   r   r“   r”   r   rW   rX   ÚACCEPTEDÚexistsrœ   r   r�   r±   r¡   r•   r–   r—   )rk   Úlatest_batchÚpending_in_batchs      r-   Ú%advance_rate_requests_batch_if_neededr¸   ö   s  € ð
 ‡�œ(Ÿ/™/×3Ñ3Ò3Øˆ	ä×Ñ×!Ñ!¨8¼K×<NÑ<N×<WÑ<WÐ!ÓX×_Ñ_ÔaØˆ	ä×&Ñ&×-Ñ-°xÐ-Ó@×JÑJÌ6Ï:É:ÐVdÓKeÓfÐgzÑ{€LØÐÜ2°8Ó<Ð<ô #×*Ñ*×1Ñ1ØØ!Ü×!Ñ!×)Ñ)ð 2ó ÷ �fƒhð	 ñ Ü�‰ØdØØ�K‰Kô	
ô
 3°8È,ÐYZÑJZÔ[Ð[à€Ir/   c                óÊ  — | j                   }|j                  t        j                  j                  k7  rt        d«      ‚| j                  t        j                  j                  k7  r't        d| j                  j                  «       › d�«      ‚t        j                  «       5  t        j                  j                  «       j                  |j                  ¬«      }|j                  t        j                  j                  k7  rt        d«      ‚t        j                  j                  | _        t!        j"                  «       | _        | j'                  g d¢¬«       t        j                  j)                  |t        j                  j                  ¬«      j+                  | j                  ¬«      j-                  t        j                  j.                  t!        j"                  «       t!        j"                  «       ¬«       | j0                  xs |j2                  xs t5        d«      }t6        j                  j9                  || j:                  |t6        j                  j                  ¬	«      }t        j                  j<                  |_        |j'                  d
dg¬«       d}t?        | j:                  dd«      }|rL|j@                  tB        jD                  jF                  tB        jD                  jH                  fv r| j:                  }tJ        j                  j9                  ||| j:                  ||tJ        j                  j<                  ¬«      }tM        |tJ        j                  j<                  «       ddd«       	 tO        |jP                  gdtS        jT                  «      tS        |jT                  «      tS        | jV                  «      tS        jT                  «      dœdd| j:                  jY                  «       xs | j:                  jZ                  › d|j\                  xs |jT                  › d�¬«       || fS # 1 sw Y   ŒÉxY w# t^        $ r t`        jc                  d«       Y | fS w xY w)zá
    Accept a rate request:
    1. Mark this rate request as ACCEPTED.
    2. Cancel all other pending rate requests for this shipment.
    3. Create an accepted Bid.
    4. Mark shipment as ASSIGNED and create the Trip.
    z Shipment is no longer available.úRate request is already r�   )r—   )rƒ   Úresponded_atÚ
updated_at©Úupdate_fieldsr³   z0.00)rk   ÚtransporterÚamountrƒ   rƒ   r¼   NÚtransporter_profile)rk   Úaccepted_bidr¿   rA   Úagreed_pricerƒ   Úbid_accepted)Útrip_idr‰   r€   Úbid_idzDriver Accepted LoadzDriver z accepted load #r�   z4Failed to notify shipper of rate request acceptance.)2rk   rƒ   r   r“   r”   rS   r   r¡   Úlowerr   rŸ   rW   Úselect_for_updaterb   r—   r´   r	   Únowr»   ÚsaverX   r]   ÚupdateÚ	CANCELLEDr„   r¢   r   r   ÚcreaterD   ÚASSIGNEDr›   Úaccount_typer   ÚAccountTypeÚDRIVERÚTRANSPORTER_DRIVERr   r   r   Ú
shipper_idr_   rž   r€   Úget_full_nameÚemailrŠ   rU   r•   r£   )Úrate_requestrk   rÀ   ÚbidrA   rE   Útrips          r-   Úhandle_rate_request_acceptrÙ     s   € ð ×$Ñ$€HØ‡�œ(Ÿ/™/×3Ñ3Ò3ÜÐ;Ó<Ð<à×Ñœk×0Ñ0×8Ñ8Ò8ÜÐ3°L×4GÑ4G×4MÑ4MÓ4OÐ3PÐPQÐRÓSÐSä	×	Ñ	Ó	ñ 27ä×#Ñ#×5Ñ5Ó7×;Ñ;¸x¿{¹{Ð;ÓKˆØ�?‰?œhŸo™o×7Ñ7Ò7ÜÐ?Ó@Ð@ä)×0Ñ0×9Ñ9ˆÔÜ$,§L¡L£NˆÔ!Ø×ÑÒ(PÐÔQô 	×Ñ×"Ñ"ØÜ×%Ñ%×-Ñ-ð 	#ó 	
÷ ‰'�\—_‘_ˆ'Ó
%§f¡fÜ×%Ñ%×/Ñ/Ü!Ÿ™›Ü—|‘|“~ð '-ô '
ð ×+Ñ+ÒZ¨x×/GÑ/GÒZÌ7ÐSYË?ˆô �k‰k× Ñ ØØ$×+Ñ+ØÜ—:‘:×&Ñ&ð	 !ó 
ˆô #Ÿ/™/×2Ñ2ˆŒØ�‰ X¨|Ð$<ˆÔ=ð ˆÜ˜,×-Ñ-Ð/DÀdÓKˆÙ�w×+Ñ+Ü×*Ñ*×1Ñ1Ü×*Ñ*×=Ñ=ð0
ñ 
ð +×1Ñ1ˆOä�|‰|×"Ñ"ØØØ$×+Ñ+Ø+ØÜ—;‘;×'Ñ'ð #ó 
ˆô 	˜4¤§¡×!5Ñ!5Ô6÷e27ðjQÜØ× Ñ Ð!Øä˜tŸw™w›<Ü" 8§;¡;Ó/Ü  ×!7Ñ!7Ó8Ü˜cŸf™f›+ñ	ð )Ø˜<×.Ñ.×<Ñ<Ó>Ò[À,×BUÑBU×B[ÑB[Ð\Ð\lÐmu×mÑmò  nOð  DL÷  DOñ  DOð  mPð  PQð  Rõ	
ð �ÐÐ÷K27ð 27ûôD ò QÜ×ÑÐOÕPà�ÐÐðQús    Â!K	P2Í3B;P> Ð2P;Ð>Q"Ñ!Q"c                óè  — | j                   t        j                  j                  k7  r't	        d| j                   j                  «       › d�«      ‚t        j                  «       5  t        j                  j                  | _         |xs dj                  «       | _
        t        j                  «       | _        | j                  g d¢¬«       ddd«       t        | j                   «       | S # 1 sw Y   Œ xY w)zh
    Reject a rate request and advance to the next batch if all requests in the batch are resolved.
    rº   r�   r1   )rƒ   Úrejection_reasonr»   r¼   r½   N)rƒ   r   r“   r¡   rS   rÇ   r   rŸ   ÚREJECTEDra   rÛ   r	   rÉ   r»   rÊ   r¸   rk   )rÖ   Úreasons     r-   Úhandle_rate_request_rejectrÞ   n  sÈ   € ð ×Ñœk×0Ñ0×8Ñ8Ò8ÜÐ3°L×4GÑ4G×4MÑ4MÓ4OÐ3PÐPQÐRÓSÐSä	×	Ñ	Ó	ñ fÜ)×0Ñ0×9Ñ9ˆÔØ)/ª°2×(<Ñ(<Ó(>ˆÔ%Ü$,§L¡L£NˆÔ!Ø×ÑÒ(dÐÔe÷	fô *¨,×*?Ñ*?Ô@ØÐ÷fð fús   Á#A&C(Ã(C1)
r$   rQ   r%   rQ   r&   rQ   r'   rQ   ÚreturnrQ   )rk   r   rß   z
list[dict])rk   r   r|   z
int | Nonerß   úlist[RateRequest])rk   r   rß   rà   )rÖ   r   rß   ztuple[Trip, RateRequest])r1   )rÖ   r   rÝ   r_   rß   r   ):Ú__doc__Ú
__future__r   ÚloggingÚdecimalr   Údjango.confr   Údjango.contrib.authr   Ú	django.dbr   r   Údjango.utilsr	   Úaccounts.modelsr
   r   r   r   Úcore.modelsr   r   r   r   r   Úcore.load_discoveryr   Úcore.countriesr   r   Úcore.pricing.servicer   Ú
api.notifyr   Úapi.traccarr   r   Úapi.trip_statusr   ÚUserÚ	getLoggerÚ__name__r•   r“   rÎ   ÚEN_ROUTEÚARRIVED_PICKUPÚLOADEDÚ
IN_TRANSITÚARRIVED_DELIVERYrY   r.   rz   r±   r¸   rÙ   rÞ   rK   r/   r-   ú<module>rù      sþ   ðñõ #ã Ý Ý  Ý .ß )Ý !ç SÓ Sß >Õ >Ý =÷õ 8Ý #ß LÝ .áÓ€Ø	ˆ×	Ñ	˜8Ó	$€ð 	‡K�K×ÑØ‡K�K×ÑØ‡K�K×ÑØ‡K�K×ÑØ‡K�K×ÑØ‡K�K× Ñ ðÐ óónðh  $ñMØðMð ðMð ó	Mó`óBTõnr/   