o
    }si                  
   @   s  d dl Z d dlZd dlZd dlZd dlZd dlmZmZ d dlmZm	Z	m
Z
 d dlmZmZmZmZmZmZmZmZ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  d d
lm!Z" d dlm#Z$ d dl%m&Z&m'Z'm(Z( d dl)m*Z+ d dl)m,Z- ede.Z/g dZ0h dZ1d{de2de2de2fddZ3de4de4fddZ5de2de6de2de2de2f
dd Z7de4de8fd!d"Z9d#e4d$e2de4fd%d&Z:e;d'Z<de2de2fd(d)Z=d*e>d+e2de2fd,d-Z?d|de4d.e2fd/d0Z@e/Ad1ed2d3 ZBe/Ad4d5d6 ZCe/jAd7d8gd9d:d; ZDe/Ad<d=d> ZEe/Ad?d@dA ZFe/jAdBd8gd9dCdD ZGe/jAdEd8gd9dFdG ZHe/jAdHd8gd9edIdJ ZIe/jAdKd8gd9edLdM ZJe/jAdNd8gd9edOdP ZKe/jAdQd8gd9dRdS ZLe/AdTedUdV ZMe/AdWedXdY ZNe/jAdZd8gd9ed[d\ ZOe/jAd]d8gd9ed^d_ ZPe/jAd`d8gd9edadb ZQe/jAdcd8gd9eddde ZRe/jAdfd8gd9edgdh ZSe/Adidjdk ZTe/Adle/Admed|dndoZUde8d$e2de8fdpdqZVe/Adredsdt ZWe/Aduedvdw ZXe/jAdxd8gd9edydz ZYdS )}    N)datetime	timedelta)get_carrierget_internal_carrierrules_from_json)
	BlueprintResponsecurrent_appflashjsonifyredirectrender_templaterequeststream_with_contexturl_for)login_required)db)eracuni)shopify)sync)woocommerceprinter)dhldpdpaket24)order_summary)
order_itemorders)ABCD>   ATBEBGCYCZDEDKEEESFIFRGRHRHUIEITLTLULVMTNLPLPTROSESISK delivery_methodcountryreturnc                 C   s*   t jd }td|}t|}t| ||S )zLReturn internal carrier key by matching delivery method against saved rules.DATABASE_PATHSHIPPING_RULES_JSON)r	   configdatabaseget_settingr   r   )r?   r@   db_path
rules_jsonrules rJ   4/var/www/warehouse.soldered.com/app/routes/orders.py_detect_carrier'   s   
rL   orderc              
   C   s   |  dp
|  dd}|  dp|  dd}|  dp |  dd}|  dp+|  d	d}|  d
p6|  dd}||||||  dd|  dddS )zCExtract shipping address from order dict for use with carrier APIs.deliveryName	buyerNamer>   deliveryStreetbuyerStreetdeliveryPostalCodebuyerPostalCodedeliveryCity	buyerCitydeliveryCountrybuyerCountryr/   
buyerEMail
buyerPhone)namestreetpostal_codecityr@   emailphoneget)rM   rZ   r[   postalr]   r@   rJ   rJ   rK   _parse_shipping_address/   s   

rc   order_numberstepstatusmessagec                 C   s    t | |||d}d| dS )zFormat a single SSE data line.)rM   re   rf   rg   data: 

)jsondumps)rd   re   rf   rg   payloadrJ   rJ   rK   
_sse_eventB   s   rm   c              	   C   sH   |  d}t|tr zt|}W n tjtfy   g }Y nw |p#g S )z6Return items list from order, deserializing if needed.items)ra   
isinstancestrrj   loadsJSONDecodeError	TypeError)rM   rn   rJ   rJ   rK   _parse_itemsM   s   

rt   itemrG   c                 C   s   |  d|  dd}|  dp|  dp|  dp|}tt|  dd}d}|r9t||}|r9| d	dp8d}||||d
S )u   Normalise a raw e-računi order item into consistent keys.

    e-računi uses 'description' for the product name and doesn't include
    warehouse location — that's looked up from our local products table.
    productCodeskur>   descriptionproductNamerZ   quantity   defaultWarehouseLocationrw   rZ   qtylocation)ra   intfloatrE   get_product)ru   rG   rw   rZ   r~   r   productrJ   rJ   rK   _resolve_itemX   s   "r   z^S\d+$c                 C   s*   t | r| S dtjtjtj ddS )zReturn a short 6-char barcode identifier for an order number.

    S-followed-by-digits orders (e.g. S10042) are used as-is.
    All other formats (e.g. 2026-00044) get a random 6-char uppercase hash
    so the barcode fits on the label.
    r>      k)_S_ORDER_REmatchjoinrandomchoicesstringascii_uppercasedigits)rd   rJ   rJ   rK   _barcode_idl   s   
r   	pdf_bytesfilenamec                 C   sh   t jt  d}t j|dd t j||}t|d}||  W d   |S 1 s-w   Y  |S )z;Save PDF bytes to ./pdfs/ directory. Returns the file path.pdfsT)exist_okwbN)ospathr   getcwdmakedirsopenwrite)r   r   pdfs_dirr   frJ   rJ   rK   	_save_pdfx   s   
r   letterc              
   c   s   | d }t jd }t| }t| }t| dd| dp"| dd}t|ddd	V  d
}d
}zE| dd}	i }
|	rG|	|
d< |	rCdnd|
d< |
rRtj|fi |
 t	|}|s]t
dt|}|d|}t|ddd| dV  W n ty } zt|ddd| V  W Y d
}~d
S d
}~ww t|dddV  d
}d
}z9t|}t|| d t|}|r|d dp|d d}t|}t|| d t|dddV  W n ty } zt|ddd| V  W Y d
}~d
S d
}~ww t|dddV  z|rtj|d d! |rtj|d d! t|ddd"V  W n ty< } zt|ddd#| V  W Y d
}~nd
}~ww t|d$dd%|  d&V  d
}d
}z| d'd d(v }|rb| d)nd
}|d*d+}|tv }|d,krtj|||d-}t|}nK|d.krtj|||d-}t|}n8|d/v rtj||||| d0d1|d2ko|d3\}}t|tr|d4n|}n|d5krd6}t|d$dd7V  |d5kr|st
d8|d5krt|d$dd9| V  W n ty } zt|d$dd:| V  W Y d
}~d
S d
}~ww t|d;dd<V  z|r!|d5kr!tj|d d! t|d;dd=V  W n tyH } zt|d;dd>| V  W Y d
}~nd
}~ww t|d?dd@V  z| dA}|smt || dB}|rmt!"||| |r|d5krt#|}|rt$|d d }tj%|||| dC z'|&dD}|' r|d5krt()| |r|d6krt(*|||  W n
 ty   Y nw t!+|dE| t|d?ddFV  W d
S  ty } zt|d?ddG| V  W Y d
}~d
S d
}~ww )HzCGenerator that yields SSE event strings while processing one order.numberrB   deliveryMethodr>   rV   rW   r{   runningu0   Updating e-računi order and creating invoice…NbuyerTaxNumberB2BB2CvatTransactionTypez create_invoice returned empty IDokInvoice  createderrorzInvoice creation failed:    u-   Downloading invoice and delivery note PDFs…_invoice.pdfr   
documentIDid_delivery_note.pdfzPDFs downloadedzPDF download failed:    u   Sending PDFs to printer…larger   zPDFs sent to printerzPDF print failed:    z	Creating u    shipment…methodOfPayment)codpouzeceu	   pouzećemtotalAmountInDomCurrr@   r/   r   )
cod_amountr   )dhl_eudhl_intdocumentCurrencyEURr   )invoice_numbercurrencyis_euutf-8pickupOSOBNOu*   Osobno preuzimanje — no shipment createdz,No tracking number returned from carrier APIzShipment created: zShipment creation failed:    u   Printing shipping label…zShipping label printedLabel print failed: r   u,   Fulfilling order on Shopify / WooCommerce…
shopify_idrO   )tracking_numbercarrierSCompletedDeliveryzOrder fulfilledzFulfillment failed: ),r	   rD   rt   rc   rL   ra   rm   r   update_ordercreate_invoice
ValueErrorget_invoice	Exceptionget_invoice_pdfr   get_delivery_note_listget_delivery_note_pdfprinter_svc	print_pdfupperlowerEU_COUNTRIESr   create_shipment	get_labelr   r   ro   bytesdecode	print_zplshopify_svcget_order_idrE   update_order_shopify_idget_fulfillment_ordersrp   fulfill_orderlstripisdigitwc_svcmark_completedadd_tracking_noteupdate_order_status)rM   r   r   rG   rn   	recipientr   
invoice_idr   
tax_numberupdate_kwargsinvoice_dataexcinvoice_pdf_bytesdelivery_pdf_bytesdelivery_notesdn_idr   	zpl_labelis_codr   r@   r   	zpl_bytesr   fulfillment_ordersfo_idwc_order_idrJ   rJ   rK   _process_single_order   s  






"






"



r   /c                     sX   ddl m} m} ddlm} tjd }tj |} fdd|D }| |}td||dS )	Nr   )get_all_usersget_all_settings)ALL_SETTINGS_FIELDSrB   c                    s   i | ]}|  |d pd qS r>   r`   ).0r   cfgrJ   rK   
<dictcomp>+  s    z"index_redirect.<locals>.<dictcomp>z
index.html)settingsusers)app.dbr   r   app.routes.settingsr   r	   rD   r   )r   r   r   rG   all_keyssettings_datar  rJ   r   rK   index_redirect"  s   
r  z/ordersc               	   C   sx   t jd } t| }|D ]#}t|dtr/zt|d |d< W q t	y.   g |d< Y qw qt
| }td||dS )NrB   rn   zorders/index.html)r   processing_orders)r	   rD   rE   get_all_ordersro   ra   rp   rj   rq   r   get_processing_ordersr   )rG   r   or  rJ   rJ   rK   orders_list1  s    


r  z/orders/refreshPOST)methodsc               
   C   s   t jd } zt tdd d}t|}t	||  W n t
y: } ztd| dddW  Y d	}~S d	}~ww t| }|D ]#}t|d
trezt|d
 |d
< W qB t
yd   g |d
< Y qBw qBtd|dS )uE   Fetch fresh orders from e-računi, upsert to DB, return HTMX partial.rB   Z   )daysz%Y-%m-%dz8<tr><td colspan="7" class="text-danger">Refresh failed: z
</td></tr>   )rf   Nrn   zpartials/order_table.htmlr   )r	   rD   r   utcnowr   strftimer   
get_ordersrE   upsert_ordersr   r   r  ro   ra   rp   rj   rq   r   )rG   	date_from
raw_ordersr   r   r
  rJ   rJ   rK   orders_refreshD  s,   



r  z/orders/queuec                  C   s    t jd } t| }td|dS )z'HTMX partial: current processing queue.rB   zpartials/queue.html)r  )r	   rD   rE   r	  r   )rG   r  rJ   rJ   rK   orders_queue]  s   

r  z/orders/<number>c                 C   s   t jd }t| |}|std|  dd ttdS t|dt	r=zt
|d |d< W n ty<   g |d< Y nw t|dt	r^zt
|d |d< W n ty]   i |d< Y nw td|d	S )
NrB   Order  not found.warningorders.orders_listrn   addresszorders/process.html)rM   )r	   rD   rE   	get_orderr
   r   r   ro   ra   rp   rj   rq   r   r   )r   rG   rM   rJ   rJ   rK   order_detaile  s$   
r   z/orders/<number>/skipc                 C   4   t jd }t| | td|  dd ttdS )NrB   r  z	 skipped.infor  )r	   rD   rE   
skip_orderr
   r   r   r   rG   rJ   rJ   rK   
order_skip{     
r%  z/orders/<number>/unskipc                 C   r!  )NrB   r  z removed from skip list.r"  r  )r	   rD   rE   unskip_orderr
   r   r   r$  rJ   rJ   rK   order_unskip  r&  r(  z/orders/<number>/notifyc           	      C   s   ddl m} tjd }tjdd}t| |}|s&tdd|  dd	d
fS tj	ddp-i }|d}||||d}|d r@dnd}tdi ||fS )z;Send customer notification email via make.com for an order.r   notify_customerrB   MAKE_ORDER_NOTIFY_URLr>   Fr  
 not foundr   r     Tsilentr   )r   r   r    NrJ   )
app.services.notificationr*  r	   rD   ra   rE   r  r   r   get_json)	r   r*  rG   webhookrM   bodyr   resultrf   rJ   rJ   rK   order_notify  s   

r7  z/orders/make-data-structurec               
   C   s  ddl } tjdd}|stddddfS | tjd	 d
 }| r'| nd}dddddddd}zddl	}|j
||dd|dfidd}W n tyc } ztdt|ddfW  Y d}~S d}~ww |jdkrntddS tdd|j d|jdd  ddfS )zaSend a sample multipart request to the Make.com webhook so it can auto-detect the data structure.r   Nr+  r>   F'MAKE_ORDER_NOTIFY_URL is not configuredr-    static
sample.pdfs   %PDF-1.4 sample invoiceTest Customerztest@example.comz3Your Soldered Electronics order has been completed!zG<h1>Sample email body</h1><p>This is a structure detection request.</p>)NameEmailSubject	html_dataContenttitler^   invoicezinvoice.pdfzapplication/pdf   )datafilestimeoutr1  r  Tr   zmake.com returned : )pathlibr	   rD   ra   r   Path	root_pathexists
read_bytesrequestspostr   rp   status_codetext)rJ  r4  sample_pdf_pathinvoice_bytesrE  reqresperJ   rJ   rK   make_data_structure  s<   


 

(rX  z/orders/notify-testc                  C   s  ddl } ddlm} tjdd}tjddpi }|dpd }|s,t	d	d
ddfS |s6t	d	dddfS | 
tjd d }| rH| nd}ddddddddddddddddddddg}g }|D ]G}	|	d dd|dd d!|	d" |	d# |	d# ddd$}
||
|d%|d&}|d' r||	d(  d)|d*d d+ qh||	d(  d,|d-d.  qhtd/d0 |D }|st	d	d1|dd2fS t	dt|d1|d3S )4zNSend test emails in all 4 templates (EN, HR, DE, Pickup) to the given address.r   Nr)  r+  r>   Tr/  r^   FzEmail address is requiredr-  r9  r8  r:  r;  ENUSDHLzTEST-EN)labelrW   r   r   r/   DPDzTEST-HRr(   zTEST-DEPickupzTEST-PICKUPr   zSoldered Electronicsr<  zUlica Testna 110000ZagrebrW   r   )r   rO   
buyerName1rX   rQ   rS   rU   rW   r   r   rP   rT   TEST1234567890)r   invoice_pdfr   r\  z: ok (make.com: response)z: FAIL r   zunknown errorc                 s   s    | ]}d |vV  qdS )FAILNrJ   )r   rW  rJ   rJ   rK   	<genexpr>  s    znotify_test.<locals>.<genexpr>z; r1  )r   sentdetails)rJ  r2  r*  r	   rD   ra   r   r3  stripr   rK  rL  rM  rN  appendallr   len)rJ  r*  r4  r5  r^   rS  rc  variantserrorsvrM   r6  all_okrJ   rJ   rK   notify_test  sT   $"rr  z/orders/<number>/print-labelsc              
   C   st  t jd }t| |}|stdd|  ddS t|}z|dp"d}tj| |dd	t	||d
d	t
|dp:d|d}tj|d| dddd |D ]>}t||}|dp]|d}tj|d |d |d | |d |durut
|nd|d}	tj|	d| d|d  ddd qMdt	| }
tdd|
 d|  dd W S  ty } ztdt|dW  Y d}~S d}~ww )!zCPrint order summary + item labels for a single order. Returns JSON.rB   Fr  r  r-  r   r   rO   r>   r   r   r   )rd   
buyer_name	num_itemsr?   totalr   smallOrder SummaryrM   
label_typeTr   metaalso_previewprice	unitPricerw   rZ   r~   r   N)rw   product_namerz   rd   warehouse_location
item_pricer   Item: r{   zPrinted z label(s) for .)r   rg   )r	   rD   rE   r  r   rt   ra   summary_labelgeneraterm  r   r   print_labelr   
item_labelr   rp   )r   rG   rM   rn   r   img_summaryru   r	raw_priceimg_itemprintedr   rJ   rJ   rK   order_print_labels   sR   



	r  z/orders/invoice-streamc                     s   t jd dd tjdddD dd s'd	d
 } tt|  ddS t    fdd}tt| dddddS )zESSE: steps 1-3 only (create invoice, get PDF, print PDF) for a batch.rB   c                 S      g | ]
}|  r|  qS rJ   rj  r   nrJ   rJ   rK   
<listcomp>2      z"invoice_stream.<locals>.<listcomp>r   r>   ,Nr   c                   s       t ddddV  d S Nr>   r   r   zNo orders specifiedrm   rJ   rJ   rJ   rK   _empty5     zinvoice_stream.<locals>._emptytext/event-streammimetypec                  3   s       D ]} t| }|st| ddd|  dV  qt| dddV  d }d }z4|dd	}|r<tj| |d
d t| }|sGtdt	|}|d|}t| ddd| dV  W n t
y{ } zt| ddt|V  W Y d }~qd }~ww t| dddV  zt|}t||  d t| dddV  W n t
y } zt| ddt|V  W Y d }~qd }~ww t| dddV  ztj|dd t| dddV  W q t
y } zt| ddt|V  W Y d }~qd }~ww dtddi dV  W d    d S 1 sw   Y  d S )Nr   r   r  r,  r{   r   u   Creating invoice…r   r>   r   )r   r   zempty invoice IDr   r   r   r   r   u   Downloading invoice PDF…r   zPDF downloadedr   u   Sending PDF to printer…r   r   zPDF sent to printerrh   doneTri   )app_contextrE   r  rm   ra   r   r   r   r   r   r   rp   r   r   r   r   rj   rk   )r   rM   r   r   r   r   inv_numr   apprG   selectedrJ   rK   r  ;  s^   



 $z invoice_stream.<locals>.generateno-cachenozCache-ControlzX-Accel-Bufferingr  headers	r	   rD   r   argsra   splitr   r   _get_current_object)r  r  rJ   r  rK   invoice_stream-  s   
&/r  z/orders/batch-itemsc                     s   t jd  dd tjdddD dd } g }| D ]F}t| }|s'qt|} fd	d|D }t	||D ]\}}|d
pF|d|d
< q9|
||dpW|dd|dp]d|d qt|dS )zLReturn enriched item data (name, SKU, location, qty) for the packing screen.rB   c                 S   r  rJ   r  r  rJ   rJ   rK   r  s  r  zbatch_items.<locals>.<listcomp>r   r>   r  Nr   c                    s   g | ]}t | qS rJ   )r   )r   itrG   rJ   rK   r  z  s    r}  r~  ra  rO   r   )r   rs  deliveryrn   r  )r	   rD   r   r  ra   r  rE   r  rt   ziprk  r   )r  r6  r   rM   	raw_itemsenrichedr  r  rJ   r  rK   batch_itemsn  s$   
&

r  z/orders/print-batch-labelsc                  C   s  t jd } tjddpi }|dpg dd }d}g }i }t|D ]\}}|ttk r0t| nt|d }t	
|| }	|	sG|| d	 q"t|	}
t|}|||< z~|	d
pZd}tj||	ddt|
|	ddt|	dprd|||d}tj|d|dddd |d7 }|
D ]D}t|| }|dp|d}tj|d |d |d ||d |durt|nd|||d	}tj|d|d|d  ddd |d7 }qW q" ty } z|| d|  W Y d}~q"d}~ww td|||dS )zKPrint order summary + item labels for each order in the batch, in sequence.rB   Tr/  r   Nr   r   r{   r,  r   r   rO   r>   r   r   )rd   rs  rt  r?   ru  r   r   
barcode_idrv  rw  rx  rz  r}  r~  rw   rZ   r~   r   )	rw   r  rz   rd   r  r  r   r   r  r  rI  r   r  ro  hash_map)r	   rD   r   r3  ra   	enumeraterm  LETTERSrp   rE   r  rk  rt   r   r  r  r   r   r  r   r  r   r   )rG   r5  order_numberstotal_printedro  r  ir   r   rM   rn   bidr   imgru   r  r  r  r   rJ   rJ   rK   print_batch_labels  sr   
 




 r  z/orders/print-test-labelsc                  C   s6  ddddddddd	d
dddd	ddddd	gdddddddddd	ddddd	ddddd	d d!dd"d	d#d$dd%d	d&d'dd(d	d)d*dd+d	d,dddd	d-d.dd/d	d0d1dd2d	d3d4ddd	d5d6dd7d	d8d9dd:d	d;d<dd=d	d>d?dd@d	dAdBddCd	dDdEdFdGd	dHdIddJd	dKdLddMd	dNdOddPd	gddQdRdSdTdUdVdFdWd	dXdYddZd	d[d\dd]d	gdd^d_d`dadbdcddded	dddfdd	d&d'dfd(d	gdg} dg}g }i }t | D ]\}}t| }t|dh }|||dh < z,tj|dh |di t|dj |dk |dl ||dm}tj|dn|dh dodpdqdr |d7 }W n ty5 }	 z|	|dh  ds|	  W Y dt}	~	ndt}	~	ww |dj D ]W}
z0t
j|
du |
dv |
dw |dh |
dx ||dy}tj|dn|dh dz|
du  dpdqdr |d7 }W q: ty }	 z|	|dh  d{|
du  d||	  W Y dt}	~	q:dt}	~	ww qtdq|||d}S )~z3Print fake labels for the packing screen test mode.S10001Marko Horvatr[  g=
ףp=@333100zArduino Uno R3r   zA1-01r}   333101zLED Strip 1m RGBr{   zB2-03333102zResistor Kit 600pcr   zA3-07)r   buyerr  ru  rn   S10002   Jana Kovačr]  g     @K@333200zRaspberry Pi 4 4GBzC1-02333201zPower Supply 5V 3AzD2-01333202zMicroSD Card 32GBzA1-03333203zHDMI Cable 1mzB3-05333204zGPIO Breakout BoardzC2-04333205zBreadboard 830ptzA2-02333206zJumper Wires M-F 40pczB1-06333207333208zCapacitor Kit 300pczA3-08333209zLED Assortment 100pczB2-09333210zArduino Nano333211zUSB-C Cable 2mzD1-03333212zHeat Shrink Tubes KitzC3-01333213zMultimeter DT830zD3-02333214zSoldering Iron 60WzD2-05333215zSolder Wire 100gzD2-06333216zRelay Module 5Vr   zB1-07333217zHC-SR04 Ultrasonic SensorzC1-08333218zL298N Motor DriverzC2-09333219zDS18B20 Temp SensorzA2-10S10003   Klaus MüllerGLSg      2@333300zESP32 Dev BoardzA2-05333301zOLED Display 0.96"zB1-04333302zDHT22 Temp SensorzA1-08
2026-00044   OŠ Nikola Tesla ZagrebOsobno preuzimanjeg     a@333400zJumper Wires 40pc M-Mr   zB3-02
   r   r   r  rn   r  ru  )rd   rs  rt  r?   ru  r   r  rv  rw  rx  Trz  z
 summary: Nrw   rZ   r~   r   )rw   r  rz   rd   r  r   r  r   rI  r  )r  r  r   r  r  rm  r   r  r   rk  r  r   )fake_ordersr  ro  r  r  r
  r   r  r  r   r  r  rJ   rJ   rK   print_test_labels  s   +
	$	0r  z/orders/print-shipping-labelc               
      s.
  ddl m} m}m}m}m} tjddpi }|dpd	 }|dp%|	 }|dp.d	 }|s;t
d	d
ddfS tjd }	t||	}
|
rLt|
nd|i}
|r[|
ds[||
d< |
dpf|
dpfd	 }t|
dpu|
dpud|}t|
 d}d}d}zC|dv rddtjtjdd }n/|dkrddtjtjdd }n|dkrd| }n|dkrd}nd|p|
dd d}W n ty } z
t|}W Y d}~nd}~ww ||}}| ||\}} fd d!}|rd"}|jd#|fd$d|d%dd&d' |d(7 }|jd#|f|d# |d) fgdd* |d+7 }|jd#|fd,| d|d#d' |d-7 }|
dp6d}|rN|jd#|fd.| d|d#d' |d-7 }|jd#|f|d# |d/ fgdd* |d+7 }|jd#|fd0d|d1dd&d' |d27 }| }d}|D ]0}|d3 | 	 }|j||d4d5|d6 kr|jd#|f|d|d4d' |d27 }|}q~|}q~|r|jd#|f|d|d4d' |d-7 }|jd#|f|d# |d) fgdd* |d+7 }|jd#|fd7d|d8dd&d' n|dv rd"}|jd#|fd9d|d:dd&d' |d;7 }|jd#|fd<d|d1d' |d%7 }|jd#|f|d# |d) fgdd* |d+7 }|jd#|fd=| d|d>dd&d' |d?7 }|jd#|fd@d|d4dd&d' |d27 }| D ]}|jd?|f|d|dAd' |dB7 }qU|d7 }|jd#|f|d# |d/ fgdd* |d+7 }|jd#|fdC| d|d1dd&d' |d%7 }|||d#||d6 d6dD n1|dkred"}|jd#|fdd|d:dd&d' |d;7 }|jd#|fd<d|d1d' |d%7 }|jd#|f|d# |d) fgdd* |d+7 }|jd#|fd=| d|d>dd&d' |d?7 }|jd#|fd@d|d4dd&d' |d27 }| D ]}|jd?|f|d|dAd' |dB7 }q|d7 }|jd#|f|d# |d/ fgdd* |d+7 }|jd#|fdC| d|d1dd&d' |d%7 }|||d#||d6 d6dD ns|dkrGdE| }d"}|jd#|fdEd|d6dd&d' |dF7 }|||d#||d6 d6dD |dF7 }|jd#|f|d|d"d' |dG7 }|jd#|f|d# |d) fgdd* |d+7 }|jd#|fd=| d|d>dd&d' |dH7 }|jd#|fdId|d#dd&d' |d?7 }|jd#|f|d# |d/ fgdd* |dJ7 }|jd#|fd@d|d4dd&d' |d27 }| D ]}|jd?|f|d|dAd' |dB7 }q|
dp*d}|rF|dK7 }|jd?|fdL| d|d1d' |dB7 }n|dkrd"}|jd#|fdMd|dHdd&d' |dN7 }|||d#||d6 d6dD |dF7 }|jd#|f|d|d"d' |dG7 }|jd#|f|d# |d) fgdd* |d+7 }|jd#|fd=| d|d>dd&d' |dH7 }|jd#|fdOd|d4dd&d' |d27 }| D ]}|jd?|f|d|dAd' |dB7 }qz!|rtj|dPdQ ntj|dP|| dRdSddT t
d|dUW S  ty } zt
d	t|ddVfW  Y d}~S d}~ww )WzYPrint a carrier-appropriate shipping label. Returns tracking_number (or None for pickup).r   )	new_label	load_fontdraw_barcodeLARGE_LABEL_WLARGE_LABEL_HTr/  rd   r>   r  r?   Forder_number requiredr-  r9  rB   r   r   rV   rW   r/   r   N)r   r   r   r[  r  r   r   r]  glszGLS-r   zCarrier not recognised: ""c                     s   g }   dr|  d    dr|  d    dd d  dd  }|r2| |   dr>|  d  | S )NrZ   r[   r\   r>   r  r]   r@   )ra   rk  rj  )linespc_cityaddrrJ   rK   _addr_linesV  s   "z)print_shipping_label.<locals>._addr_linesrD  (   u   GREŠKA - SHIPPING LABEL4   boldfillfontJ   r   r     u   Narudžba:  8   zDostava:   r   u   Greška:$   .   r  "   )r  P   u   RUČNO KREIRAJTE OTPREMNICU,   zDHL EXPRESSF   ^   z[MOCK LABEL]u   Narudžba: *   <   z
Primatelj:&   2   z
Tracking: )xywidthheightr  j   0   >   u   RUČNO KREIRATI GLS OTPREMNICU   r   z	Dostava: zOSOBNO PREUZIMANJEX   zKupac:r   r   z	 Shippingrx  rz  )r   r     ) app.labels.renderr  r  r  r  r  r   r3  ra   rj  r   r	   rD   rE   r  dictrL   rc   r   r   r   r   r   r   rp   rR  	rectangler  
textlengthr   r   r  )r  r  r  r  r  r5  rd   r  r?   rG   rM   r@   r   r   r   	error_msgr   whr  drawr  r  
del_methodwordslinewordtestgls_barcoderW  rJ   r  rK   print_shipping_label  s   

	&*((*&*"*"
&"*,&
&*,
&"*,&
&*,

& "*,&*&
&(
& "*,&
& r$  z/orders/cancel-packingc            !   
   C   s  ddl m} m}m}m} tjddpi }|dpd }|dp#d }|s0t	dd	d
dfS t
jd }t||}|rAt|}|r|dpN|dpN| }	|dpWd }
|dp`d }|dpid }|dprd }|dp{d }|dpd }|dpd }|dpd }|dpd }|dpd }|dpd }|d}|dpd }n|}	d }
 } } }}d } } } } }}d}d}|o| |
 k}||}}| ||\}}d}|jd|f|d|d dd!d" |d#7 }|jd|f|d |d$ fgdd% |d&7 }|jd|fd'd|d(dd!d" |d)7 }td|	|r=d*| nd|
| d+|  |gD ]}|jd,|f|d|d-d" |d.7 }qK|dur}|jd,|fd/|d0d+| d|d-d" |d.7 }|d17 }|jd|f|d |d2 fgdd% |d37 }|jd|fd4d|d(dd!d" |d)7 }|r|r| |	 kr|n|	}|r|| d+|  |fn|
| d+|  |f}td|g||pdD ]}|jd,|f|d|d-d" |d.7 }q|d17 }|jd|f|d |d$ fgdd% |d57 }|jd|fd6d|d7dd!d" |d87 }|jd|fd9d|d)dd!d" |d,7 }|jd|fd:d|d)dd!d" |d;7 }|jd|fd<d|d)dd!d" ztj|d=|d>d?dd@ t	ddAW S  ty }  zt	dt| d
dBfW  Y d} ~ S d} ~ ww )Cz7Print a cancellation notice label on the large printer.r   )r  r  r  r  Tr/  rd   r>   rs  Fr  r-  r9  rB   ra  rO   rQ   rS   rU   rW   r   rN   rP   rR   rT   rV   r   r   r   r   NrD  r  r  r  r  n   r   r  r  zINVOICE:r  r  zTax: r  r	  r
  r  zTotal: z.2fr   r   r  z	SHIPPING:   zCANCELLED PROCESSINGr  D   zINVOICE HAS BEEN MADEzFINISH PROCESSINGr   zWITH E-RACUNIr   	Cancelledrx  rz  rH  r  )r  r  r  r  r  r   r3  ra   rj  r   r	   rD   rE   r  r  r   rR  r  filterr   r  r   rp   )!r  r  r  r  r5  rd   rs  rG   rM   buyer_name1buyer_streetbuyer_postal
buyer_citybuyer_country	buyer_taxdel_name
del_street
del_postaldel_citydel_countryr?   ru  r   ship_differsr  r  r  r  r  r   ship_name_line	ship_addrrW  rJ   rJ   rK   cancel_packing  s   


&*&
&
0*&&&*&&& r8  z/orders/confirm-packedc                  C   s  ddl m}  tjd }tjdd}tjddpi }|dp d }|d	p)d p-d
}|s8tddddfS tjdddk}|rIt	
d|nd
}|rW|sWtddddfS t	||}|rdt|}nO|srtdd| dddfS dddddddddddd d!d"dd#d#dd$d%d&d'd(d)d*d*dd+d+d,dddd-d.dd/}	|	|d0d0d1dddddd}
||d2|
}|r||d3< dd
l}tjt d4}|tjd5 d6 }| r| nd
}d
}d
}tj|| d7}tj|| d8}tj|rt|d9}| }W d
   n	1 sw   Y  n|r|}tj|r;t|d9}| }W d
   n	1 s5w   Y  n|r@|}| |||||d:}|d; rPd<nd=}td>i ||fS )?zNSend shipping confirmation email after packing + shipping label scan verified.r   r)  rB   r+  r>   Tr/  rd   r   NFr  r-  r9  MAKE_TEST_MODE1MAKE_TEST_EMAILuI   Test mode is on but no test email address is set in Settings → make.comr  r,  r.  Horvatr  zIlica 42r_  r`  r/   r[  )rO   ra  rQ   rS   rU   rW   r   r   u   Kovačr  zVukovarska 1521000Splitr]  u   Müllerr  u   Hauptstraße 880331u   Münchenr(   r  r  u   Šegavčeva 9r^  r  )r  r  r  r  r<  zTestna ulica 1)r   rX   rX   r   r:  r;  r   r   rb)r   rc  delivery_note_pdfr   r  r1  rJ   )r2  r*  r	   rD   ra   r   r3  rj  r   rE   rF   r  r  rJ  r   r   r   r   rK  rL  rM  rN  r   read)r*  rG   r4  r5  rd   r   	test_mode
test_emailrM   _test_ordersbaserJ  r   rS  sample_pdf_bytesrc  rA  invoice_pathdn_pathr   r6  rf   rJ   rJ   rK   confirm_packed  s   



rJ  z/orders/process-streamc                     s   t jd tjdd} dd | dD dd s)d	d
 }tt| ddS t    fdd}tt| dddddS )zzSSE endpoint: auto-process selected orders.

    Query param: orders=S1001,S1002,S1003,S1004 (comma-separated, max 4)
    rB   r   r>   c                 S   r  rJ   r  r  rJ   rJ   rK   r    r  z"process_stream.<locals>.<listcomp>r  Nr   c                   s   r  r  r  rJ   rJ   rJ   rK   empty_stream  r  z$process_stream.<locals>.empty_streamr  r  c                  3   s       tD ]\} }| ttk rt|  nt| d }t|}|s3t|ddd| dV  q
t|ddd| d| d	V  t|}zt|	d
pMd}t
j||	ddt||	ddt|	dped||d}tj|d|dddd |D ]?}t|}|	dp|	d}	tj|d |d |d ||d |	d urt|	nd ||d}
tj|
d|d|d  ddd qyW n ty } zt|ddd| V  W Y d }~nd }~ww t||dE d H  q
td di}d!| d"V  W d    d S 1 sw   Y  d S )#Nr{   r   r   r  z not found in DBr   zStarting order z (re  r   r   rO   r>   r   r   )rd   rs  rt  r?   ru  r   r   rv  rw  rx  Trz  r}  r~  rw   rZ   r~   r   )rw   r  rz   rd   r  r  r   r   r  r   )r   r  rh   ri   )r  r  rm  r  rp   rE   r  rm   rt   ra   r  r  r   r   r  r   r  r   r   rj   rk   )r  r   r   rM   rn   r   r  ru   r  r  r  r   rl   r  rJ   rK   r    sf   
 

	

""z process_stream.<locals>.generater  r  r  r  r  )order_numbers_rawrK  r  rJ   r  rK   process_stream{  s"   

7rM  z/orders/dump-samplez/orders/dump-sample/<number>c              
   C   s  ddl }tjd }g }| r@zt| }|d ||j|ddd W n ty? } z|d| d	 W Y d}~nd}~ww |d
 | rt| |}|sY|d|  d nldD ]}t	|
|trzzt|| ||< W q[ tyy   Y q[w q[||j|ddd n>t|}|s|d n1|d }dD ]}t	|
|trzt|| ||< W q ty   Y qw q||j|ddd d|}	tjt d}
t|
ddd}||	 W d   n1 sw   Y  t|	ddS )uP   Dump raw e-računi API response + local DB row for an order to sample_order.txt.r   NrB   u)   === RAW e-računi API (SalesOrderGet) ===r   x   )indentr  z=== RAW API ERROR: z ===z=== LOCAL DB ROW ===r  z not found in DB.)rn   r  z&No orders in DB yet. Run a sync first.ri   zsample_order.txtr  r   )encodingz
text/plainr  )pprintr	   rD   r   r  rk  pformatr   rE   ro   ra   rp   rj   rq   r  r   r   r   r   r   r   r   )r   rQ  rG   sectionsrawr   rM   fieldr   txtout_pathr   rJ   rJ   rK   orders_dump_sample  sZ   





rX  c              	   C   s   t d|}t|}| D ]:}t|dtr/zt|d |d< W n ty.   g |d< Y nw |dp9|dd}t	|dd|||d< q| S )zIDeserialise items and add a 'carrier' field (standardised shipping name).rC   rn   rV   rW   r>   r   r   )
rE   rF   r   ro   ra   rp   rj   rq   r   r   )r   rG   rH   rI   r
  r@   rJ   rJ   rK   _enrich_orders  s   rY  z/orders/processingc                  C   s$   t jd } t| }tt|| dS )z/Return Processing orders from local DB as JSON.rB   r  )r	   rD   rE   r	  r   rY  rG   r   rJ   rJ   rK   orders_processing_json  s   

r[  z/orders/listc                  C   s*   t jd } tj| dgd}tt|| dS )z(Return all orders from local DB as JSON.rB   Draft)exclude_statusesr  )r	   rD   rE   r  r   rY  rZ  rJ   rJ   rK   orders_list_json$  s   
r^  z/orders/syncc                     sN   t jd  tjddpi } | dd fdd}tt| dd	d
ddS )uA   SSE stream: sync orders (and optionally products) from e-računi.rB   Tr/  sync_productsFc               
   3   s    z,t  D ]} dtd| i dV  qr,t  D ]} dtd| i dV  qW n" tyO } zdtd| dd dV  W Y d }~nd }~ww dtddi dV  d S )Nrh   rg   ri   zError: T)rg   r   r  )sync_svcsync_ordersrj   rk   r_  r   )msgr   rG   do_productsrJ   rK   r  5  s   ,zorders_sync.<locals>.generater  r  r  r  r  )r	   rD   r   r3  ra   r   r   )r5  r  rJ   rc  rK   orders_sync-  s   
re  r   )N)Zrj   r   r   rer   r   r   app.services.shipping_mappingr   r   r   flaskr   r   r	   r
   r   r   r   r   r   r   flask_loginr   r  r   rE   app.servicesr   r   r   r   r`  r   r   r   r   app.services.shippingr   r   r   
app.labelsr   r  r   r  __name__	orders_bpr  r   rp   rL   r  rc   r   rm   listrt   r   compiler   r   r   r   r   router  r  r  r  r   r%  r(  r7  rX  rr  r  r  r  r  r  r$  r8  rJ  rM  rX  rY  r[  r^  re  rJ   rJ   rJ   rK   <module>   s    0
	

 !





'7
,?;Z !X^
U4	