
    {is                       d dl m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 d dlmZ d d	lmZ d d
lmZmZmZmZmZ d Zd ZdddddddddddddZdddddddd d!d"d#d$dZd%d&d'd(d)d*Zd+Zd)Z  ed,-       G d. d/             Z! ed,-       G d0 d1             Z" ed,-       G d2 d3             Z# ed,-       G d4 d5             Z$dLd6Z%dMd7Z&dNd8Zd9 Z'dOd:Z(dPd;Z)dQd<Z*dRd=Z+d> Z,dSd?Z-dMd@Z.dTdAZ/dTdBZ0dC Z1dUdDZ2	 	 	 	 	 	 	 	 dVdEZ3	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dWdFZ4dGdH	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dXdIZ5	 	 	 	 	 	 	 	 	 	 dYdJZ6dZdKZ7yG)[    )annotations)
monthrange)defaultdict)	dataclass)date	timedelta)Decimal)Iterable)Booking)Prefetch)calculate_age_ongenerate_guest_nightsget_booking_guest_countget_prefetched_guestswith_guest_night_prefetchc                    t        |       S )z
    Apply required DB optimizations:
    - property -> FK -> select_related
    - guests -> reverse FK -> prefetch_related
    )r   )querysets    '/backend/structures/city_tax_service.pywith_city_tax_prefetchr      s     %X..    c                    t        |       S )zA
    Use prefetched guests if available, fallback otherwise.
    )shared_get_prefetched_guests)bookings    r   r   r      s     (00r   JanuaryFebruaryMarchAprilMayJuneJulyAugust	SeptemberOctoberNovemberDecember)                        	   
         JanFebMarAprJunJulAugSepOctNovDecMedicalStudentRefugeeResidentMinor)medicalstudentrefugeeresidentminorzOther ExemptionT)frozenc                  z    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   d
ed<   ded<   dZded<   dZded<   y)CityTaxGuestSubjectstrkeyint
booking_id
int | Noneguest_id	full_nameemailphonezdate | Nonedate_of_birth
str | Noneexplicit_exemption_labelFboolis_synthetic_minoris_main_guestN)__name__
__module____qualname____annotations__rW   rX    r   r   rI   rI   N   sB    	HONJJ(($$M4r   rI   c                      e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   d
ed<   d
ed<   d
ed<   d
ed<   ded<   ded<   y)CityTaxNightRecordr   rL   reservation_idrJ   	guest_keyrN   rO   monthnight_indexrV   
is_taxable	is_exemptis_platformis_overflowrT   exemption_bucketr	   rateNrY   rZ   r[   r\   r]   r   r   r_   r_   \   sE    
JNJO  
Mr   r_   c                  r    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   ded
<   ded<   ded<   ded<   y)CityTaxBookingContextr   r   rL   total_guests_countchildren_countadults_countoverlap_nights_in_periodrJ   main_guest_namemain_guest_emailmain_guest_phonesource_labelrV   platform_exemptNrj   r]   r   r   rl   rl   l   s>    !!r   rl   c                  ,    e Zd ZU ded<   ded<   ded<   y)CityTaxReportResultdictpreview_payload
list[dict]export_rowslist[CityTaxNightRecord]night_recordsNrj   r]   r   r   rw   rw   z   s    ++r   rw   c                   t               }| s|S t        | t        t        t         f      r| n| g}|D ]V  }|t	        |      j                  d      D ]4  }|j                         j                         }|s$|j                  |       6 X |S )N,)	set
isinstancelisttuplerJ   splitstriploweradd)platform_valuetokens
raw_valuesrawtokencleaneds         r   normalize_platform_tokensr      s    uF ntUC&89 	 
 ;X^^C(Ekkm))+G

7# )  Mr   c                V    | yt        |       j                         j                         S )N )rJ   r   r   )reason_values    r   normalize_reasonr      s(    |""$**,,r   c                    t        | |      S N)shared_calculate_age_on)rS   on_dates     r   r   r      s    "='::r   c                    |xs i }t        |       }||v rt        t        ||               S | |v rt        t        ||                S | |v r||    S |S r   )rJ   r	   )rb   rates_overridemonthly_rate_mapdefault_rate	month_strs        r   resolve_rate_for_monthr      si    #)rNE
IN"s>)4566s>%0122  &&r   c                    i }| xs g D ]N  }t        |      }|st        j                  |t        |      j	                         j                               ||<   P |st        j                         S |S r   )r   EXEMPTION_REASON_LABELSgetrJ   r   titlecopy)exemption_reasons
configuredreason
normalizeds       r   build_configured_exemption_mapr      st    !#J#)r)%f-
!8!<!<K%%'"

:	 * &++--r   c                    g }| j                   |j                  d       | j                  |j                  d       | j                  |j                  d       |S )Nmax_taxable_nightsr   minor_age_limit)r   appendr   r   )settingsmissings     r   $get_missing_city_tax_settings_fieldsr      sV    G""*+,$~&'()Nr   c                    | d   }| d   }| d   }t        ||d      }|dk(  rt        |dz   dd      }nt        ||dz   d      }t        t        ||dz               }|||fS )Nyear
from_monthto_monthr&   r1   )r   r   range)periodr   r   r   
start_dateend_exclusivemonths_ranges          r   build_period_boundsr      sz    &>D%Jj!HdJ*J2~TAXq!,T8a<3j(Q,78L}l22r   c           	         ddl m} |j                  j                  | |      D ci c]+  }|j                  t        t        |j                              - c}S c c}w )Nr&   )CityTaxMonthlyRate)	structurer   )modelsr   objectsfilterrb   r	   rJ   ri   )r   r   r   ri   s       r   build_monthly_rate_mapr      sY    * '..55	PT5UUD 	

GC		N++U  s   0Ac                F   t        | xs d      j                  d      D cg c]#  }|j                         s|j                         % }}|sy|D cg c]  }|j                          }}d|v ry|d   }|j                         dk(  ry|j	                         S c c}w c c}w )	Nr   r   zDirect bookingairbnbAirbnbr   zbooking.comzBooking.com)rJ   r   r   r   r   )raw_platformpr   r   lowereds        r   pick_source_labelr      s    !$\%7R!8!>!>s!CQ!CAqwwyaggi!CFQ*01&u{{}&G171IE{{}%;;= R 2s   BBBc                (    | j                          dS )Nz 00:00:00 UTC)	isoformat)
date_values    r   fmt_date_timer      s    ""$%]33r   c                *    | sy| j                  d      S )Nr   z%Y-%m-%d %H:%M:%S UTC)strftime)dt_values    r   fmt_datetimer      s    455r   c                L    |dk(  rt        | dz   dd      S t        | |dz   d      S )Nr1   r&   )r   r   rb   s     r   month_end_exclusiver      s/    {D1Ha##eai##r   c                6    t        | |t        | |      d         S )Nr&   )r   r   r   s     r   month_last_dayr     s    eZe4Q788r   c                @    | sy | D ]  }|j                   s|c S  | d   S Nr   )rX   )
guest_listguests     r   
main_guestr     s,    L  a=r   c           	         | rt        | dd      sy t        t        | dd             }|st        S |j                  |t        j                  |t        |      j                                     S )Nis_city_tax_exemptFcity_tax_exemption_reason)getattrr   OTHER_EXEMPTION_LABELr   r   rJ   r   )r   configured_exemptionsnormalized_reasons      r   rU   rU     si    ';UC(8SUY)Z[$$ $$##$5s;L7M7S7S7UV r   c                   t        t        | j                  xs d      d      t        t        | j                  xs d      d      z   }|dk  rg S t	        t        t        |             d       }|d t        t        |      |       }d}|D ]0  }t        |j                  | j                        }|&||k  s,|dz  }2 |t        |      z
  }	t        t        | j                  xs d      |z
  d      }
t        |
|	      }
t        |	|
z
  d      }|D cg c]  }t        d| j                   d|j                   | j                  |j                  |j                  xs d|j                  xs d|j                   xs d|j                  t#        ||      |j$                  	       }}t'        |
      D ]B  }|j)                  t        d| j                   d	|dz    | j                  d dddd d d
	             D t'        |      D ]A  }|j)                  t        d| j                   d|dz    | j                  d dddd d              C |d | S c c}w )Nr   c                <    | j                    | j                  xs dfS r   )rX   id)r   s    r   <lambda>z&build_guest_subjects.<locals>.<lambda>-  s    u222EHHMBr   rK   r&   zbooking-z-guest-r   )	rK   rM   rO   rP   rQ   rR   rS   rU   rX   z-synthetic-child-T)	rK   rM   rO   rP   rQ   rR   rS   rU   rW   z-synthetic-adult-)rK   rM   rO   rP   rQ   rR   rS   rU   )maxrL   ro   rn   sortedr   r   minlenr   rS   check_in_daterI   r   rP   rQ   rR   rU   rX   r   r   )r   r   r   rm   guestsconsidered_guestsknown_minorsr   age_on_checkinremaining_slotssynthetic_minor_countsynthetic_adult_countsubjectsindexs                 r   build_guest_subjectsr     s   
 S!5!5!:;Q?#G""'a(	C  Q	"7+,BF ES[2D!EFL")%*=*=w?T?TU%.?*JAL #
 )3/@+AAOG$:$:$?a @< OQRS 5G2G GK" ' 'E 	7::,gehhZ8zzXXoo+++#++#--%=%&  --	
 '  $ ,-wzzl*;EAI;G"::")-#'
	
 . ,-wzzl*;EAI;G"::")-		
 . ''((_s   BIc        
           | j                   | j                  k  rg S g }
| j                   | j                  z
  j                  }|D ]9  }i }t        |      D ]%  }| j                  t	        |      z   }||cxk  r|k  sn +|j
                  }|j                  }|s-|j                  r!t        |j                  |      }|d uxr ||k  }d }d}d}d}|	rd}nQ|j                  r|j                  }d}n6|r	t        }d}n+|j                  |d      }|dk(  s||k\  rd}d}n
d}|dz   ||<   |dz   }|
j                  t        || j                  |j                  |j                   |||||	||t#        ||||                   ( < |
S )NdaysFTr   r&   rb   r   r   r   r   r`   ra   rO   rb   rc   rd   re   rf   rg   rh   ri   )check_out_dater   r   r   r   rb   rW   rS   r   rU   MINORS_LABELr   r   r_   r   rK   rO   r   )r   r   period_startperiod_end_exclusivecapr   r   r   r   is_platform_exemptrecordstotal_nightssubjectmonthly_taxable_countnight_offset
night_daterb   is_minorage_on_nightrh   rd   re   rg   month_countrc   s                            r   build_night_records_for_bookingr  n  s    !6!66	(*G**W-B-BBHHL02!,/L ..1MMJ JE1EE$$E11H 5 5/0E0EzR't3V8V#JIK! 	11#*#C#C  	#/  	 477qA!8{c1"&K $I!%J3>?)%0 '*KNN"##*::%kk$-- +)' 2 +%5/#'5)9%1	O 0	 B Nr   N)platform_exemption_labelsc        
          89:;<= t        | d      rt        |       } t        |      \  }
}:|d   }t        |j	                               t
        hz  8:D ci c]  }|t               dt        d      d c};:D ci c]  }|t               dd c}<:D ci c]  }|t               dt        d      d c}=t        :fd      }t               }t               }t               }t               }t        d      }g }i }i }| D ]j  }t        t        |j                  xs d      d      }t        t        |j                  xs d      d      }t        |      }|dk  r[t        |j                  |
      }t        |j                  |      }t        ||z
  j                   d      }|dk  rt#        |j$                        }t'        |j)                  |            }t+        t-        |            } t/        |       }!t1        ||||||!r|!j2                  nd|!r|!j4                  r|!j4                  nd|!r|!j6                  r|!j6                  ndt9        |j$                        |	
      ||j:                  <   m t=        t?        | |
||
      d       }"|"D ]  }#|jA                  |#jB                         |jE                  |#jF                        }$t'        |$xr |$jH                        }tK        |#jL                        }%d }&d}'d}(d})|rd}(n|%r@|jE                  |%tN        jE                  |%tQ        |%      jS                                     }&d}(nX|#jT                  r	t
        }&d}(nC|#jB                  |#jV                  f}*|jE                  |*d      }+|dk(  s|+|k\  rd})d}(n
d}'|+dz   ||*<   |jY                  t[        |#j\                  |#jF                  |#jB                  |#j^                  |#jV                  |#j`                  |'|(||)|&tc        |#jV                  |||                    |D ]  },|,jd                  r;|,jV                     d   jA                  |,jB                         ;|,jV                     dxx   dz  cc<   ;|,jV                     dxx   |,jf                  z  cc<   |jA                  |,jB                         ||,jf                  z  }|,jh                  r=|,jV                     d   jA                  |,jB                         =|,jV                     dxx   dz  cc<   =|,jV                     dxx   |,jf                  z  cc<   |jA                  |,jB                         6|,jj                  rb<|,jV                     d   jA                  |,jB                         <|,jV                     dxx   dz  cc<   |jA                  |,jB                         |,jl                  s|,jh                  r||,jl                     |,jV                     d   jA                  |,jB                         ||,jl                     |,jV                     dxx   dz  cc<   ! g }-g }.:D ]~  }|-jY                  tn        |   tq        ;|   d         ;|   d   ts        tu        ;|   d         d      d       |.jY                  tn        |   tq        <|   d         <|   d   d        i }/|jw                         D ]W  \  }09|08vrty        9fd:D              }1|1dk  r%:D cg c]$  }tn        |   tq        9|   d         9|   d   d& c}|/|0<   Y ty        <fd:D              }2ty        8:fd|jw                         D              }3ty        =fd:D              }4tq        |      }5|5ty        ;fd:D              ty        <fd:D              z   |3z   |4z   k7  rt{        d      tq        |      ty        ;fd:D              |2|3z   |4z   ts        tu        |      d      d |-ty        ;fd!:D              ty        ;fd":D              ts        tu        |      d      dd#|.ty        <fd$:D              |2dd#|/tq        |      ty        =fd%:D              ts        tu        ty        =fd&:D                    d      t=        |	xs g       d'tq        |      |5ts        tu        |      d      dd(}6t}        ||:|)      }7t        |6|7|*      S c c}w c c}w c c}w c c}w )+Nselect_relatedr   r   0)r   nightstaxr   r  c                 F    D  ci c]  } | t               dd c} S c c} w )Nr   r  )r   )rb   r   s    r   r   z+calculate_city_tax_report.<locals>.<lambda>  s/    %
% ceq11%
 
s   r   )
r   rm   rn   ro   rp   rq   rr   rs   rt   ru   )r   r   r   c                H    | j                   | j                  | j                  fS r   )r   rM   ra   )items    r   r   z+calculate_city_tax_report.<locals>.<lambda>  s    $))T__dnnEr   r   FTr&   r   r   r   r  r  r'   )rb   r   r  r  )rb   r   r  c              3  .   K   | ]  }|   d      ywr  Nr]   ).0rb   month_buckets     r   	<genexpr>z,calculate_city_tax_report.<locals>.<genexpr>  s     !Z\E,u"5h"?\   c              3  .   K   | ]  }|   d      ywr  r]   r  rb   section_b_monthlys     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s      ^Q]!25!9(!CQ]r  c              3  J   K   | ]  \  }}|v rD ]  }||   d       ywr  r]   )r  reason_labelr  rb   allowed_labelsr   s       r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s?      !*C&L,>)!E 	UH% " 	&*Cs    #c              3  .   K   | ]  }|   d      ywr  r]   r  rb   section_d_monthlys     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s        8Du% *r  c              3  .   K   | ]  }|   d      ywr  r]   r  rb   section_a_monthlys     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s     IL5e$X.Lr  c              3  .   K   | ]  }|   d      ywr  r]   r  s     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s     KlU&x0lr  zCity tax calculation mismatchc              3  .   K   | ]  }|   d      ywr  r]   r"  s     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s       "@Lu!%(2r  )guests_subject_to_taxtaxable_nightsexempt_nightstotal_to_payc              3  @   K   | ]  }t        |   d            ywr   Nr   r"  s     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  %      IUC)%0:;   c              3  .   K   | ]  }|   d      ywr  r]   r"  s     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s       DP5%e,X6Lr  )rowstotalc              3  @   K   | ]  }t        |   d            ywr+  r,  r  s     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  r-  r.  c              3  .   K   | ]  }|   d      ywr  r]   r  s     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s       @Lu!%(2r  c              3  .   K   | ]  }|   d      yw)r  Nr]   r  s     r   r  z,calculate_city_tax_report.<locals>.<genexpr>  s       #=IE!%(/\r  )r   r  r  	platforms)summary	section_a	section_b	section_c	section_dtotals)booking_contextsr}   r   r   )ry   r{   r}   )@hasattrr   r   r   valuesr   r	   r   r   rL   ro   rn   r   r   r   r   r   r   platformrV   intersectionr   r   r   rl   rP   rQ   rR   r   r   r   r   r   ra   r   rM   ru   r   exemption_reasonr   rJ   r   r  rb   r   r_   r   rO   rc   r   rd   ri   rf   rg   rh   MONTH_NAMESr   roundfloatitemssum
ValueErrorbuild_export_rowsrw   )>bookingsr   r   r   r   r   r   r   platform_exemptionsr  r   r   r   rb   section_c_monthlytaxable_guest_keysoverflow_guest_keysplatform_guest_keysall_guest_keys	total_taxr}   r<  taxable_night_countsr   ro   rn   rm   overlap_startoverlap_end_exclusiverp   booking_platform_tokensr   guests_listprimary_guestguest_nightsguest_nightbooking_contextr   rh   rd   re   rg   guest_month_keyr  recordsection_a_rowssection_b_rowssection_c_outputr  total_reason_nightssection_b_total_nightssection_c_total_nightsplatform_nights_totaltotal_guest_nightsry   r{   r  r  r   r#  r  r   s>                                                           @@@@@@r   calculate_city_tax_reportrd    s~	    x)*)(37J67R4L&&>D.5578L>IN "!E 	#%1WS\BB! "!E 	#%1--! "!E 	#%1WS\BB! $	
 %%UNI.0M9;793w338q91=S!7!7!<1=qA4W="G11<@ #G$:$:<P Q#&(=(M'S'SUV#W #q(";G<L<L"M!"9"F"FGZ"[\09:";/'<1)%%=7DM33"4AmFYFY]00_a4AmFYFY]00_a*7+;+;<.(
$% > %!5+		
 FL $;001*..{/E/EF!/"Uo6U6UV,[-I-IJ
	I488!'++%)*002  I!!+I*44k6G6GHO.22?AFK!Q&+9K*K" 	!
8Ca$_5 %%*55%//$--!'''33%#.'!1+%++#1%5!-		
I $t  fll+H599&:J:JKfll+H5:5fll+E2fkkA2""6#3#34$Ifll+H599&:J:JKfll+H5:5fll+E2fkkA2##F$4$45fll+H599&:J:JKfll+H5:5##F$4$45$$V-?-?f556v||DXNRR   f556v||DXNRSSN)  , NN$U+/6x@A+E28<U#4U#;E#BCQG		
 	$U+/6x@A+E28<	
 " &7&=&=&?"l~-!!Z\!ZZ!# &*
 &	 %U+l51(;<&u-h7
 &*
& '@ ! ^Q] ^^  !*;*A*A*C!     8D   ]+ILII
KlK
K	L
 	!  	  899 &));%<! "@L"  '()'( "%	"2A6
 # IU   DP  U9-q1
 # IU  1	
 &-. @L  s #=I#      9 ?R@	
 .)(y)1-
[2Oh $)#!	K '# ON*
s   c+=c0c5 )c:c                    t        t              }|D ],  }||j                  |j                  f   j	                  |       . g }t        |j                          fd      }|D ]W  \  }}	 |   }
|
j                  }|||	f   }t        |D ch c]  }|j                   c}      }|sE|d   }|d   t        d      z   }t        d |D              }t        d |D              }t        d	 |D              }t        d
 |D              }t        |D ch c]  }|j                  s|j                   c}      }t        d |D        t        d            }|d   j                  }t        |      }||z   |z   |z   }|j	                  i d|j                   ddd|
j"                  dt%        |      dt%        |      d|j&                  r|j&                  j(                  ndd||z
  j*                  d|
j,                  d|
j.                  d|
j0                  dt3        |j4                  xs d      dt7        |j8                        d|
j:                  dt3        |      dt3        |      dt=        t3        |      d      d |||||||
j>                  |
j@                  |	tB        |	   |tE        ||	      d!       Z |S c c}w c c}w )"Nc                N    | d      j                   j                  | d   | d   fS )Nr   r&   )r   r   )r  r<  s    r   r   z#build_export_rows.<locals>.<lambda>  s.    T!W%--;;GG
r   r   r   r&   r   c              3  :   K   | ]  }|j                   sd   ywr&   N)rd   r  r[  s     r   r  z$build_export_rows.<locals>.<genexpr>  s     SoFARARao   c              3  h   K   | ]*  }|j                   r|j                  s|j                  sd  , ywri  )re   rf   rg   rj  s     r   r  z$build_export_rows.<locals>.<genexpr>  s1      
)(:(:6CUCU )s   02c              3  :   K   | ]  }|j                   sd   ywri  )rf   rj  s     r   r  z$build_export_rows.<locals>.<genexpr>  s     $[_6HZHZQ_rk  c              3  :   K   | ]  }|j                   sd   ywri  )rg   rj  s     r   r  z$build_export_rows.<locals>.<genexpr>  s     ToFASASaork  c              3  N   K   | ]  }|j                   s|j                    y wr   rd   ri   rj  s     r   r  z$build_export_rows.<locals>.<genexpr>  s     LV&:K:KV[[   %%r  r   first_guest_statussuccessclient_full_namecheck_in	check_outrental_namer   nights_countrm   adultschildrenfinal_price
created_atsourceguest_city_tax_base_amountrental_tax_amountestimated_total_city_taxr'   estimated_ordinary_nights)estimated_exempt_nights estimated_platform_exempt_nightsoverflow_guest_countoverflow_nightsvalidation_totalclient_emailclient_phonerb   month_labelall_guest_nightsr   )#r   r   r`   rb   r   r   keysr   r   r   rF  r   rg   ra   r	   ri   r   rq   r   propertynamer   rm   ro   rn   rD  total_pricer   r|  rt   rC  rr   rs   MONTH_SHORTr   )r<  r}   r   r   records_by_booking_and_monthr[  r0  sorted_keysrM   rb   contextr   monthly_recordsunique_datessegment_startsegment_end_exclusiveordinary_nightsr(  platform_exempt_nightsr  r  rP  
month_rater  r  s   `                        r   rH  rH    sG    U``dTe $f&;&;V\\%JKRRSYZ   D$))+
K )
E":.//6
E7JKIvv{{IJ$Q ,R 09!3D DSoSS 
)
 

 "%$[_$[![ToTT",;RO&v?Q?QVOR 
 LLCL
	 %Q',,
/*]:_LOeegjj$i #G$;$; M-8	
 ]+@A 8H8Hw//44b !6!F L L %g&@&@ '.. G22 uW%8%8%=A> l7+=+=> '.. -eJ.? $U:%6  +E%	2BA,F!" ,_#$ ,94J(<#2$4 ' 8 8 ' 8 8*51$4"0u"=9	
; )| Ku J Ss   K
K
#K
c                   t        t        | j                  xs d            }| j                  r| j                  s|S | j                  | j                  k  rt        d      S 	 | j
                  j                  }|j                  s|S g }| j                  j                  }| j                  t        d      z
  j                  }||k  r{|| j                  j                  k(  r| j                  j                  nd}||k(  r#| j                  t        d      z
  j                  nd}|j                  |||d       |dz  }||k  r{t        |j                        }t        |j                         }	t        d      }
|D ]  }t#        | g|i t        t        |j$                  xs d            t'        | j
                  |d         |j(                  |j*                  ||	t-        |j                   xs g       	
      }|
t/        d
 |j0                  D        t        d            z  }
 |
j3                  t        d            S # t        $ r |cY S w xY w)z
    Reuse the existing guest-night city tax engine for a single booking so
    financial documents stay aligned with the city-tax/ISTAT reporting logic.
    r   z0.00r&   r   r1   )r   r   r   r  r   )
rI  r   r   r   r   r   r   r   rJ  r  c              3  N   K   | ]  }|j                   s|j                    y wr   rp  rj  s     r   r  z3calculate_booking_city_tax_total.<locals>.<genexpr>w  s     Q';Vv?P?PV[[';rq  z0.01)r	   rJ   city_taxr   r   r   city_tax_settings	Exception	is_activer   r   rb   r   r   r   r   rJ  rd  r   r   r   r   r   rF  r}   quantize)r   fallback_amountr   yearly_segmentscurrent_year
final_yearr   r   r   rJ  rP  r   results                r    calculate_booking_city_tax_totalr  =  s5   
 c'"2"2"7a89O  (>(>!6!66v$$66 "$O((--L((9!+<<BBJ
*
$4@GDYDYD^D^4^W**00de
 z) ##iQ&77>> 	
 	$($	
 	 *
$  ;8;U;UV3H4P4PQI!*Y X%:%:%?a!@A3G4E4Evf~V'::$44"7 3&*8+G+G+M2&N
 	SQv';';QCL
 	
	 "$ gfo..a  s   "H8 8II)returnset[str])r  rJ   )r   r   r  rN   )r  dict[str, str])r  z	list[str])r   rx   r  ztuple[date, date, list[int]])r   rL   r  dict[int, Decimal])r   r   r  rJ   )r   rL   rb   rL   r  r   )r   r  r  rT   )r   r   r   r  r   rL   r  list[CityTaxGuestSubject])r   r   r   r  r   r   r   r   r   rL   r   rL   r   r	   r   rV   r  r|   )rI  zIterable[Booking]r   rx   r   r	   r   r  r   rL   r   rL   r   r  rJ  r  r  zlist[str] | Noner  rw   )
r<  z dict[int, CityTaxBookingContext]r}   r|   r   z	list[int]r   rL   r  rz   )r   r   r  r	   )8
__future__r   calendarr   collectionsr   dataclassesr   datetimer   r   decimalr	   typingr
   bookings.modelsr   django.db.modelsr   services.guest_night_servicer   r   r   r   r   r   r   r   rB  r  r   r   r   rI   r_   rl   rw   r   r   r   r   r   r   r   r   r   r   r   r   r   rU   r   r  rd  rH  r  r]   r   r   <module>r     s   "  # ! $   # % /1       *  $
  
  
  $   $
 
 
 $, , ,,-;$346$9L)L))L) L) 	L)^TT (T 	T
 T 
T T T T TD 37__ _
 _ )_ _ _ *_ "_  0_ _D	S6S ,S 	S
 S Sl>/r   