+
    ÞDj…- ã                   ó 	  € R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt	^ RI
t	^ RIHt ^ RIt^ RIHtHtHtHtHtHtHt ^ RIHt  ^ RIt^ RIHtHtHtHtHtHtH t H!t!H"t" ]! R]#4      t$R]R]R	]R
]R]R]PJ                  PL                  RR/t']PP                  PS                  ]PP                  PU                  ]PP                  PU                  ]+4      4      RRR4      t,],t-Rt.. RNRNRNRNRNRNRNRNRNRNRNRNRNRNR NR!NR"NR#NR$NR%NR&NR'NR(NR)NR*NR+NR,NR-NR.NR/NR0NR1NR2NR3NR4NR5NR6NR7NR8NR9NR:NR;NR<NR=NR>NR?NR@NRANRBNRCNt/RD t0RE t1RF t2RG t3RH t4RI t5RJ t6RK t7RL t8RM t9RN t:RO t;RP t<]$P{                  RQRR.RS7      RT 4       t>]$P{                  RURRRV.RS7      RW 4       t?]$P{                  RXRYRZ.RS7      R[ 4       t@R\ tA]$P{                  R]RRRV.RS7      R^ 4       tBR_R`R_Ra^Rb^Rc^/RdR`RdRa^Rb^Rc^/ReR`ReRa^Rb^Rc^//tCRf tDRg tE]$P{                  RhRV.RS7      Ri 4       tF]$P{                  RjRYRZ.RS7      Rk 4       tG]$P{                  RlRm.RS7      Rn 4       tH]$P{                  RoRR.RS7      Rp 4       tIRq tJRr tK]$P{                  RsRR.RS7      Rt 4       tL]$P{                  RuRRRV.RS7      Rv 4       tM]$P{                  RwRR.RS7      Rx 4       tN]$P{                  RyRR.RS7      Rz 4       tO]$P{                  R{RV.RS7      R| 4       tP]$P{                  R}. R¥ORS7      R~ 4       tQR tRR€ tSR� tTR‚ tU]$P{                  RƒRV.RS7      R„ 4       tV]$P{                  R…RV.RS7      R† 4       tW]$P{                  R‡RV.RS7      Rˆ 4       tX]$P{                  R‰Rm.RS7      RŠ 4       tY]$P{                  R‹RZ.RS7      RŒ 4       tZ]$P{                  R�. R¦ORS7      RŽ 4       t[]$P{                  R�RR.RS7      R� 4       t\]$P{                  R‘RRRY.RS7      R’ 4       t]]$P{                  R“RRRY.RS7      R” 4       t^]$P{                  R•RV.RS7      R– 4       t_]$P{                  R—RRRY.RS7      R˜ 4       t`]$P{                  R™RV.RS7      Rš 4       ta]$P{                  R›RR.RS7      Rœ 4       tb]$P{                  R�RR.RS7      Rž 4       tc]$P{                  RŸR R¡/R¢7      ]$P{                  R£4      R¤ 4       4       tdR#   ] d    Rt EL~i ; i)§z‹
PartsInventory blueprint: Flask port of the PartsInventory server APIs.
Serves API endpoints and a built React SPA under /partsinventory.
N)Údatetime)Ú	BlueprintÚResponseÚjsonifyÚredirectÚrequestÚ	send_fileÚsend_from_directory)Úsecure_filename)	ÚPARTSINV_CLIENT_DISTÚPARTSINV_DB_HOSTÚPARTSINV_DB_NAMEÚPARTSINV_DB_PASSWORDÚPARTSINV_DB_PORTÚPARTSINV_DB_USERÚPARTSINV_IMAGE_SEARCH_API_KEYÚPARTSINV_IMAGE_SEARCH_CXÚPARTSINV_UPLOAD_DIRÚpartsinventoryÚhostÚportÚuserÚpasswordÚdatabaseÚcursorclassÚ
autocommitFÚdatazdb-config.jsonzPhttps://api.github.com/repos/KiCad/kicad-footprints/git/trees/master?recursive=1Ú0402Ú0603Ú0805Ú1206Ú1210Ú1812Ú2010Ú2512zSOT-23zSOT-223zSOT-89zSOT-143zSOT-323zSOT-363zSOD-123zSOD-323zSOD-523zDO-214AA (SMB)zDO-214AB (SMC)zDO-214AC (SMA)zTO-220zTO-92zQFN-16zQFN-24zQFN-32zQFN-48zQFP-32zQFP-44zQFP-64zTQFP-32zTQFP-44zTQFP-64zSOIC-8zSOIC-14zSOIC-16zSOP-8zTSSOP-8zTSSOP-14zTSSOP-16zSSOP-16zMSOP-8zDFN-8zDIP-8zDIP-14zDIP-16zLQFP-64zLQFP-100zBGA-64zBGA-100zUSB-C Receptaclec                  óÖ  € \         P                  P                  \        R R/R7      p \         P                  P	                  V ^R7      ;_uu_ 4       p\
        P                  ! VP                  4       P                  R4      4      pRRR4       . pXP                  R. 4       F•  pVP                  R4      ;'       g    RpVP                  R	4      '       g   K7  R
V9  d   K@  VP                  R
^4      w  rgVP                  R	^4      ^ ,          pV'       d	   V'       g   K  VP                  V RV 24       K—  	  \        \        P!                  V4      4      #   + '       g   i     LÛ; i)z
User-AgentzPartsInventory/1.0)Úheaders©Útimeoutúutf-8NÚtreeÚpathÚ z
.kicad_modz.pretty/Ú:)Úurllibr   ÚRequestÚ_KICAD_TREE_API_URLÚurlopenÚjsonÚloadsÚreadÚdecodeÚgetÚendswithÚsplitÚrsplitÚappendÚlistÚdictÚfromkeys)	ÚreqÚresponseÚpayloadÚnamesÚitemr+   ÚlibÚmodÚfp_names	            ÚA/workplace/Workspace/Software/Server/blueprints/partsinventory.pyÚ_fetch_kicad_footprintsrG   j   s  € Ü
�.‰.×
 Ñ
 Ô!4¸|ÐMaÐ>bÐ
 Ó
c€CÜ	�‰×	Ñ	 ¨RÐ	×	0Ô	0°HÜ—*’*˜XŸ]™]›_×3Ñ3°GÓ<Ó=ˆ÷ 
1à€EØ—‘˜F BÖ'ˆØ�x‰x˜Ó×%Ð% 2ˆØ�}‰}˜\×*Ò*ÙØ˜TÔ!ÙØ—:‘:˜j¨!Ó,‰ˆØ—*‘*˜\¨1Ó-¨aÕ0ˆßŸ'ÙØ�‰˜�u˜A˜g˜YÐ'Ö(ñ (ô ”—‘˜eÓ$Ó%Ð%÷ 
1×	0ús   Á4EÅE(	c           	      ó.  € \        4       pV'       g	   R ^ R^ R^ /# V P                  R4       V P                  4       pV Uu/ uF.  q3R,          \        VP	                  R4      ;'       g    ^ 4      bK0  	  pp^ p^ p. p\        \        4      p\        V4       FM  w  ršVP	                  V
4      pVf   V^,          pMV^ 8X  d
   V^,          pVP                  W¨V	,           34       KO  	  V'       d   V P                  RV4       R VRVR\        V4      /# u upi )ÚaddedÚreactivatedÚtotalzWSELECT name, COALESCE(is_active, 0) AS is_active FROM footprints WHERE source = 'kicad'ÚnameÚ	is_activea*  
            INSERT INTO footprints (name, source, sort_order, is_active)
            VALUES (%s, 'kicad', %s, 1)
            ON DUPLICATE KEY UPDATE
                source = VALUES(source),
                sort_order = VALUES(sort_order),
                is_active = VALUES(is_active)
            )
rG   ÚexecuteÚfetchallÚintr6   ÚlenÚ_DEFAULT_FOOTPRINTSÚ	enumerater:   Úexecutemany)ÚcurÚkicad_namesÚexisting_rowsÚrÚexistingrI   rJ   r@   Ú	base_sortÚirL   Ú
was_actives   &           rF   Ú_sync_kicad_footprintsr]   ~   s  € Ü)Ó+€KßØ˜˜M¨1¨g°qÐ9Ð9à‡K�KÐiÔjØ—L‘L“N€MÙANÓOÁ¸A�&•	œ3˜qŸu™u [Ó1×6Ð6°QÓ7Ò7Á€HÐOà€EØ€KØ€GÜÔ'Ó(€IÜ˜[Ö)‰ˆØ—\‘\ $Ó'ˆ
ØÒØ�Q�J‰EØ˜1Œ_Ø˜1ÕˆKØ�‰˜¨!�mÐ,Ö-ñ *÷ Ø�‰ðð ô
	
ð �U˜M¨;¸ÄÀ[ÓAQÐRÐRùò5 Ps   Á (DÁ)Dc                  óP   € \        4       p R \        V P                  R R4      4      /# )Ú
showQrCodeT)Ú_load_overrideÚboolr6   ©Úoverrides    rF   Ú_effective_ui_settingsrd   ¢   s)   € ÜÓ€Hà”d˜8Ÿ<™<¨°dÓ;Ó<ðð ó    c                  ó  € \         P                  P                  \        4      '       g   / #  \	        \        R RR7      ;_uu_ 4       p \
        P                  ! V 4      uuRRR4       #   + '       g   i     R# ; i  \         d    / u # i ; i)rX   r)   ©ÚencodingN)Úosr+   ÚexistsÚ_DB_OVERRIDE_FILEÚopenr2   ÚloadÚ	Exception)Úfs    rF   r`   r`   ©   s_   € Ü�7‰7�>‰>Ô+×,Ò,Øˆ	ðÜÔ# S°7×;Õ;¸qÜ—9’9˜Q“<÷ <×;×;Ó;ûäô ØŠ	ðús/   ­A< ÁA(Á
A< Á(A9	Á3A< Á9A< Á<BÂBc                 ó  € \         P                  ! \         P                  P                  \        4      R R7       \        \        RRR7      ;_uu_ 4       p\        P                  ! W^R7       RRR4       R#   + '       g   i     R# ; i)T©Úexist_okÚwr)   rg   )ÚindentN)ri   Úmakedirsr+   Údirnamerk   rl   r2   Údump)r   ro   s   & rF   Ú_save_overriderx   ³   sM   € Ü‡K‚K”—‘—‘Ô 1Ó2¸TÕBÜ	Ô ¨w×	7Õ	7¸1Ü�	Š	�$ !Õ$÷ 
8×	7×	7Ò	7ús   ÁA7Á7B	c                  ó@  € \        4       p R V P                  R \        4      R\        V P                  R\        4      4      RV P                  R\
        4      RV P                  R\        4      RV P                  R\        4      R\        P                  P                  RR/# )r   r   r   r   r   r   r   F)r`   r6   r   rP   r   r   r   r   ÚpymysqlÚcursorsÚ
DictCursorrb   s    rF   Ú_effective_db_configr}   ¹   s‚   € ÜÓ€Hà�—‘˜VÔ%5Ó6Ø”�H—L‘L Ô)9Ó:Ó;Ø�—‘˜VÔ%5Ó6Ø�H—L‘L Ô-AÓBØ�H—L‘L Ô-=Ó>Ø”w—‘×1Ñ1Ø�eðð re   c                  óÊ  € \        4       p V P                  R 4      ;'       g    \        ;'       g    RP                  4       p\        P
                  P                  V4      '       d   V# \        P
                  P                  \        P
                  P                  \        4      4      p\        P
                  P                  \        P
                  P                  W!4      4      # )Ú	uploadDirÚpartsinventory_uploads)r`   r6   r   Ústripri   r+   Úisabsrv   Ú__file__ÚabspathÚjoin)rc   Ú
upload_dirÚbases      rF   Ú_effective_upload_dirrˆ   Æ   s‹   € ÜÓ€HØ—,‘,˜{Ó+×^Ð^Ô/B×^Ð^ÐF^×eÑeÓg€JÜ	‡w�w‡}�}�Z× Ò ØÐÜ�7‰7�?‰?œ2Ÿ7™7Ÿ?™?¬8Ó4Ó5€DÜ�7‰7�?‰?œ2Ÿ7™7Ÿ<™<¨Ó9Ó:Ð:re   c                ó¾  aa€ T;'       g    RP                  RR4      P                  4       pV'       g   R# . o\        4       oVV3R lpV! V4       VP                  R4      '       d   V! V\	        R4      R 4       MV! RV 24       S FK  p\
        P                  P                  W4      p\
        P                  P                  V4      '       g   KI  Vu # 	  S Fý  p\
        P                  P                  V4      w  rg\
        P                  P                  V4      w  r‰V'       g   KO  \
        P                  P                  W4      p
\
        P                  P                  V
4      '       g   K•  \        P                  ! \
        P                  P                  W¨ R24      4       F.  p\
        P                  P                  V4      '       g   K*  Vu u # 	  Kÿ  	  R# )zFFind an on-disk upload file for a DB path across legacy path variants.r,   Ú\Ú/Nc                 óà   <€ T ;'       g    R P                  RR4      P                  4       P                  R4      pV'       d   VS9   d   R# SP                  V4       SP	                  V4       R# )r,   rŠ   r‹   N)Úreplacer�   ÚlstripÚaddr:   )ÚrelÚrel_normÚseenÚvariantss   & €€rF   r�   Ú*_resolve_existing_upload_file.<locals>.addØ   sT   ø€ Ø—I�I˜2×&Ñ& t¨SÓ1×7Ñ7Ó9×@Ñ@ÀÓEˆß˜8 tÔ+ÙØ�‰�ÔØ�‰˜Ö!re   úuploads/ú.*)r�   r�   ÚsetÚ
startswithrQ   ri   r+   r…   Úisfiler8   ÚsplitextÚisdirÚglob)Úupload_rootÚstored_pathÚrawr�   r�   Ú	candidateÚrel_dirÚrel_nameÚstemÚ_extÚabs_dirÚmatchr’   r“   s   &&          @@rF   Ú_resolve_existing_upload_filer§   Ï   sV  ù€ à×Ð˜"×
%Ñ
% d¨CÓ
0×
6Ñ
6Ó
8€CßÙà€HÜ‹5€Dö"ñ ˆ„HØ
‡~�~�j×!Ò!ÙˆC”�J“Ð Ð!Õ"áˆh�s�eÐÔãˆÜ—G‘G—L‘L Ó2ˆ	Ü�7‰7�>‰>˜)×$Ô$ØÒñ ó ˆÜŸG™GŸM™M¨#Ó.ÑˆÜ—W‘W×%Ñ% hÓ/‰
ˆßÙÜ—'‘'—,‘,˜{Ó4ˆÜ�w‰w�}‰}˜W×%Ò%ÙÜ—Y’YœrŸw™wŸ|™|¨G°v¸R°[ÓAÖBˆEÜ�w‰w�~‰~˜e×$Ô$Ø”ó Cñ ñ re   c                  ó>   € \         P                  ! R/ \        4       B # )N© )rz   Úconnectr}   r©   re   rF   Ú_get_dbr«   ú   s   € Ü�?Š?Ñ4Ô1Ó3Ñ4Ð4re   c                  óŠ   € \        4       p R V R ,          RV R,          RV R,          RV R,          RV R,          '       d   R/# R/# )r   r   r   r   r   z****N)r}   )Úcfgs    rF   Ú_db_health_payloadr®   þ   sT   € Ü
Ó
 €Cà��F•Ø��F•Ø��F•Ø�C˜
•OØ˜c *Ÿoœo�Fðð ð
 48ðð re   c                 ó  € \         P                  ! 4       pVP                  R 4       VP                  R\        P                  ! 4       P                  4        R24       VP                  R4       V P                  4       ;_uu_ 4       pVP                  R4       VP                  4       pV Uu. uF  qDR,          NK  	  ppV EFs  pVP                  RV R24       VP                  4       pV'       d   VP                  R4      MR	pV'       g   KN  VP                  R
V R24       VP                  RV R24       VP                  V R24       VP                  RV R24       VP                  4       p	V	'       g   K»  \        V	^ ,          P                  4       4      p
RP                  V
 Uu. uF	  pRV R2NK  	  up4      pV	 F\  pRP                  V
 Uu. uF"  q°P                  VP                  V4      4      NK$  	  up4      pVP                  RV RV RV R24       K^  	  VP                  R4       EKv  	  R	R	R	4       VP                  R4       VP                  4       # u upi u upi u upi   + '       g   i     L@; i)z-- PartsInventory full backup
z-- Generated at z

zSET FOREIGN_KEY_CHECKS = 0;

zÎ
            SELECT TABLE_NAME
            FROM information_schema.TABLES
            WHERE TABLE_SCHEMA = DATABASE()
              AND TABLE_TYPE = 'BASE TABLE'
            ORDER BY TABLE_NAME
            Ú
TABLE_NAMEzSHOW CREATE TABLE `Ú`zCreate TableNz
-- Table: Ú
zDROP TABLE IF EXISTS `z`;
z;

zSELECT * FROM `z, zINSERT INTO `z` (z
) VALUES (z);
zSET FOREIGN_KEY_CHECKS = 1;
)ÚioÚStringIOÚwriter   ÚnowÚ	isoformatÚcursorrN   rO   Úfetchoner6   r;   Úkeysr…   ÚliteralÚgetvalue)ÚconnÚoutrU   Ú
table_rowsrX   Útable_namesÚ
table_nameÚ
create_rowÚ
create_sqlÚrowsÚcolumnsÚcÚcol_sqlÚrowÚvalss   &              rF   Ú_sql_dump_for_current_dbrÊ   	  s  € Ü
�+Š+‹-€CØ‡I�IÐ/Ô0Ø‡I�IÐ ¤§¢£×!9Ñ!9Ó!;Ð <¸DÐAÔBØ‡I�IÐ/Ô0à	�‰�Œ˜#Ø�‰ðô	
ð —\‘\“^ˆ
Ù0:Ó;±
¨1˜—�±
ˆÐ;ä%ˆJØ�K‰KÐ-¨j¨\¸Ð;Ô<ØŸ™›ˆJß;E˜Ÿ™¨Ô7È4ˆJßÙØ�I‰I˜
 : ,¨bÐ1Ô2Ø�I‰IÐ.¨z¨l¸$Ð?Ô@Ø�I‰I˜˜ EÐ*Ô+à�K‰K˜/¨*¨°QÐ7Ô8Ø—<‘<“>ˆDßÙÜ˜4 �7Ÿ<™<›>Ó*ˆGØ—i‘i±7Ó ;±7¨a 1 Q C q£±7Ñ ;Ó<ˆGÛ�Ø—y‘yÁGÓ!LÁG¸q§,¡,¨s¯w©w°q«zÖ":ÁGÑ!LÓM�Ø—	‘	˜M¨*¨°S¸¸	ÀÈDÈ6ÐQUÐVÖWñ ð �I‰I�d�Oñ' &÷ 
ðD ‡I�IÐ-Ô.Ø�<‰<‹>Ðùò1 <ùò" !<ùâ!L÷= 
�úsD   Â&I1Â,I"Â=AI1ÄA,I1Å:1I1Æ+I'Æ:I1Ç(I,Ç=<I1É"I1É1J	c                 óÀ  € V P                  4       ;_uu_ 4       pVP                  R 4       VP                  R4       VP                  R4       VP                  R4       VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R	4        VP                  R
4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4        VP                  R4       \	        \
        4       F  w  r#VP                  RW234       K  	  RRR4       V P                  4        R#   \        P                   d     EL³i ; i  \        P                   d     EL½i ; i  \        P                   d     ELÇi ; i  \        P                   d     ELÑi ; i  \        P                   d     ELÛi ; i  \        P                   d     ELåi ; i  \        P                   d     ELïi ; i  \        P                   d     ELùi ; i  \        P                   d     ELi ; i  \        P                   d     ELi ; i  \        P                   d     ELi ; i  \        P                   d     EL!i ; i  \        P                   d     EL+i ; i  \        P                   d     EL5i ; i  \        P                   d     EL?i ; i  \        P                   d     ELIi ; i  \        P                   d     ELSi ; i  \        P                   d     EL]i ; i  \        P                   d     ELgi ; i  \        P                   d     ELqi ; i  + '       g   i     ELS; i)ay  
            CREATE TABLE IF NOT EXISTS footprints (
                id INT AUTO_INCREMENT PRIMARY KEY,
                name VARCHAR(255) NOT NULL,
                source VARCHAR(20) NOT NULL DEFAULT 'custom',
                sort_order INT NOT NULL DEFAULT 0,
                is_active TINYINT(1) NOT NULL DEFAULT 1,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                UNIQUE KEY uq_footprints_name (name),
                INDEX idx_footprints_active_sort (is_active, sort_order, name)
            )
            a#  
            CREATE TABLE IF NOT EXISTS categories (
                id INT AUTO_INCREMENT PRIMARY KEY,
                parent_id INT NULL,
                source_partkeepr_id INT NULL,
                name VARCHAR(255) NOT NULL,
                description TEXT,
                sort_order INT DEFAULT 0,
                FOREIGN KEY (parent_id) REFERENCES categories(id) ON DELETE SET NULL,
                INDEX idx_parent (parent_id),
                UNIQUE KEY uq_categories_source_partkeepr_id (source_partkeepr_id)
            )
            a8  
            CREATE TABLE IF NOT EXISTS storage_locations (
                id INT AUTO_INCREMENT PRIMARY KEY,
                parent_id INT NULL,
                source_partkeepr_id INT NULL,
                name VARCHAR(255) NOT NULL,
                description TEXT,
                sort_order INT DEFAULT 0,
                FOREIGN KEY (parent_id) REFERENCES storage_locations(id) ON DELETE SET NULL,
                INDEX idx_parent (parent_id),
                UNIQUE KEY uq_storage_locations_source_partkeepr_id (source_partkeepr_id)
            )
            aL  
            CREATE TABLE IF NOT EXISTS parts (
                id INT AUTO_INCREMENT PRIMARY KEY,
                category_id INT NULL,
                storage_location_id INT NULL,
                overstock_location_id INT NULL,
                source_partkeepr_id INT NULL,
                name VARCHAR(255) NOT NULL DEFAULT '',
                description TEXT,
                part_number VARCHAR(255) NOT NULL DEFAULT '',
                quantity INT NOT NULL DEFAULT 0,
                overstock_quantity INT NOT NULL DEFAULT 0,
                unit VARCHAR(50) DEFAULT '',
                average_price DECIMAL(12,4) NOT NULL DEFAULT 0,
                minimum_stock_level INT NOT NULL DEFAULT 0,
                comment TEXT,
                barcode VARCHAR(255) NULL,
                datasheet_url VARCHAR(1024) NULL,
                datasheet_file_path VARCHAR(1024) NULL,
                datasheet_thumbnail_path VARCHAR(1024) NULL,
                manufacturer VARCHAR(255) NULL,
                footprint VARCHAR(255) NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL,
                FOREIGN KEY (storage_location_id) REFERENCES storage_locations(id) ON DELETE SET NULL,
                FOREIGN KEY (overstock_location_id) REFERENCES storage_locations(id) ON DELETE SET NULL,
                INDEX idx_category (category_id),
                INDEX idx_storage (storage_location_id),
                INDEX idx_overstock_storage (overstock_location_id),
                INDEX idx_barcode (barcode),
                UNIQUE KEY uq_parts_source_partkeepr_id (source_partkeepr_id),
                UNIQUE KEY unique_barcode (barcode)
            )
            ac  
            CREATE TABLE IF NOT EXISTS part_images (
                id INT AUTO_INCREMENT PRIMARY KEY,
                part_id INT NOT NULL,
                file_path VARCHAR(1024) NULL,
                original_filename VARCHAR(255) NULL,
                url VARCHAR(1024) NULL,
                source ENUM('uploaded', 'internet') NOT NULL,
                is_primary TINYINT(1) NOT NULL DEFAULT 0,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (part_id) REFERENCES parts(id) ON DELETE CASCADE,
                INDEX idx_part (part_id)
            )
            zVALTER TABLE part_images ADD COLUMN original_filename VARCHAR(255) NULL AFTER file_pathz>ALTER TABLE categories ADD COLUMN source_partkeepr_id INT NULLz]ALTER TABLE categories ADD UNIQUE KEY uq_categories_source_partkeepr_id (source_partkeepr_id)zEALTER TABLE storage_locations ADD COLUMN source_partkeepr_id INT NULLzkALTER TABLE storage_locations ADD UNIQUE KEY uq_storage_locations_source_partkeepr_id (source_partkeepr_id)zeALTER TABLE storage_locations ADD COLUMN slot_unusable TINYINT(1) NOT NULL DEFAULT 0 AFTER sort_orderz9ALTER TABLE parts ADD COLUMN source_partkeepr_id INT NULLzUALTER TABLE parts ADD COLUMN overstock_location_id INT NULL AFTER storage_location_idzUALTER TABLE parts ADD COLUMN overstock_quantity INT NOT NULL DEFAULT 0 AFTER quantityz”ALTER TABLE parts ADD CONSTRAINT fk_parts_overstock_location FOREIGN KEY (overstock_location_id) REFERENCES storage_locations(id) ON DELETE SET NULLzIALTER TABLE parts ADD INDEX idx_overstock_storage (overstock_location_id)zSALTER TABLE parts ADD UNIQUE KEY uq_parts_source_partkeepr_id (source_partkeepr_id)zVALTER TABLE parts ADD COLUMN average_price DECIMAL(12,4) NOT NULL DEFAULT 0 AFTER unitz[ALTER TABLE parts ADD COLUMN minimum_stock_level INT NOT NULL DEFAULT 0 AFTER average_pricezHALTER TABLE parts ADD COLUMN comment TEXT NULL AFTER minimum_stock_levelzbALTER TABLE parts ADD COLUMN datasheet_thumbnail_path VARCHAR(1024) NULL AFTER datasheet_file_pathzKALTER TABLE parts ADD COLUMN footprint VARCHAR(255) NULL AFTER manufacturerz;ALTER TABLE parts MODIFY COLUMN footprint VARCHAR(255) NULLzYALTER TABLE footprints ADD COLUMN source VARCHAR(20) NOT NULL DEFAULT 'custom' AFTER namez?ALTER TABLE footprints MODIFY COLUMN name VARCHAR(255) NOT NULLa  
                INSERT INTO footprints (name, source, sort_order, is_active)
                VALUES (%s, 'default', %s, 1)
                ON DUPLICATE KEY UPDATE
                    sort_order = VALUES(sort_order),
                    is_active = VALUES(is_active)
                N)r¸   rN   rz   ÚOperationalErrorrS   rR   Úcommit)r½   rU   r[   rL   s   &   rF   Ú_ensure_tablesrÎ   5  s!  € Ø	�‰�Œ˜#Ø�‰ðô	
ð 	�‰ðô	
ð 	�‰ðô	
ð 	�‰ð"ô$	
ðJ 	�‰ðô	
ð 	Ø�K‰KÐpÔqð	Ø�K‰KÐXÔYð	Ø�K‰KÐwÔxð	Ø�K‰KÐ_Ô`ð	Ø�K‰Kð  Fô  Gð	Ø�K‰KØwôð
	Ø�K‰KÐSÔTð	Ø�K‰KÐoÔpð	Ø�K‰KÐoÔpð	Ø�K‰Kð gôð
	Ø�K‰KÐcÔdð	Ø�K‰KÐmÔnð	Ø�K‰KÐpÔqð	Ø�K‰KÐuÔvð	Ø�K‰KÐbÔcð	Ø�K‰KÐ|Ô}ð	Ø�K‰KÐeÔfð	Ø�K‰KÐUÔVð	Ø�K‰KÐsÔtð	Ø�K‰KÐYÔZô !Ô!4Ö5‰GˆAØ�K‰Kðð �	ö	ñ 6÷o 
ðD 	‡K�K†Møô{ ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ûô ×'Ñ'ô 	Úð	ú÷k 
�ˆúsj  ™AQÁ0HÂH8ÂIÂ&I0Â8JÃ
J(ÃKÃ.K Ä K<ÄLÄ$L4Ä6MÅM,ÅNÅ,N$Å>O ÆOÆ"O8Æ4PÇP0Ç+QÈH5È1QÈ4H5È5QÈ8IÉQÉIÉQÉI-É)QÉ,I-É-QÉ0J	ÊQÊJ	Ê	QÊJ%Ê!QÊ$J%Ê%QÊ(KÊ=QË KËQËKËQËKËQË K9Ë5QË8K9Ë9QË<LÌQÌLÌQÌL1Ì-QÌ0L1Ì1QÌ4MÍ	QÍMÍQÍM)Í%QÍ(M)Í)QÍ,NÎQÎNÎQÎN!ÎQÎ N!Î!QÎ$N=Î9QÎ<N=Î=QÏ OÏQÏOÏQÏO5Ï1QÏ4O5Ï5QÏ8PÐQÐPÐQÐP-Ð)QÐ,P-Ð-QÐ0Q	ÑQÑQ	Ñ	QÑQ	c                 ó´   € \        V 4      p\        VP                  4       4       F/  w  r#\        V\        4      '       g   K  VP                  4       W&   K1  	  V# )N)r<   r;   ÚitemsÚ
isinstancer   r·   )rÈ   r¾   ÚkeyÚvalues   &   rF   Ú_dateifyrÔ   û  sD   € Ü
ˆs‹)€CÜ˜3Ÿ9™9›;Ö'‰
ˆÜ�eœX×&Ô&Ø—‘Ó(ˆC‹Hñ (ð €Jre   z/api/healthÚGET)Úmethodsc                  ó    € \        R R/4      ^È3# )ÚokT)r   r©   re   rF   ÚhealthrÙ     s   € ä�D˜$�<Ó  #Ð%Ð%re   z/api/categoriesÚPOSTc                  óÜ  € \        4       p  \        V 4       V P                  4       ;_uu_ 4       p\        P                  R 8X  dG   VP                  R4       VP                  4       p\        V4      uuRRR4       V P                  4        # \        P                  ! RR7      ;'       g    / pVP                  RVP                  R4      VP                  RR4      VP                  R	R4      VP                  R
^ 4      34       VP                  RVP                  34       V P                  4        \        VP                  4       4      ^É3uuRRR4       V P                  4        #   + '       g   i     MS; i  \         dC   pT P                  4        \        R\!        T4      /4      R3u Rp?T P                  4        # Rp?ii ; i T P                  4        R#   T P                  4        i ; i)rÕ   z]SELECT id, parent_id, name, description, sort_order FROM categories ORDER BY sort_order, nameNT©ÚsilentzYINSERT INTO categories (parent_id, name, description, sort_order) VALUES (%s, %s, %s, %s)Ú	parent_idrL   r,   ÚdescriptionÚ
sort_orderú&SELECT * FROM categories WHERE id = %sÚerroréô  ©r«   rÎ   r¸   r   ÚmethodrN   rO   r   ÚcloseÚget_jsonr6   Ú	lastrowidrÍ   r¹   rn   ÚrollbackÚstr©r½   rU   rÄ   r@   Úes        rF   Úcategories_rootrí     sq  € ä‹9€DðÜ�tÔØ�[‰[�]Œ]˜cÜ�~‰~ Ô&Ø—‘Ð{Ô|Ø—|‘|“~�Ü˜t“}÷	 ‰]ð" 	�
‰
�ô ×&Ò&¨dÔ3×9Ð9°rˆGØ�K‰KØkØ—‘˜[Ó)¨7¯;©;°v¸rÓ+BÀGÇKÁKÐP]Ð_aÓDbÐdk×doÑdoÐp|Ð~ó  eAð  Bôð �K‰KÐ@À3Ç=Á=ÐBRÔSØ�K‰KŒMÜ˜3Ÿ<™<›>Ó*¨CÐ/÷ ‰]ð" 	�
‰
�÷# �]ûô ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úð ð" 	�
‰
Žøˆ�
‰
�úóf   Œ#E6 ¯AE#Á0
E6 ÂE#Â)BE#Å
E6 Å#E3	Å.E6 Å2G Å3E6 Å6GÆ'F>Æ(GÆ)G Æ>GÇG ÇG+z/api/categories/<int:item_id>ÚPUTÚDELETEc                 óä  € \        4       p \        V4       VP                  4       ;_uu_ 4       p\        P                  R 8X  Ed   \        P
                  ! RR7      ;'       g    / pVP                  RVP                  R4      VP                  R4      VP                  R4      VP                  R^ 4      V 34       VP                  RV 34       VP                  4       pV'       g:   VP                  4        \        R	R
/4      R3uuRRR4       VP                  4        # VP                  4        \        V4      uuRRR4       VP                  4        # VP                  RV 34       VP                  ^ 8X  d:   VP                  4        \        R	R
/4      R3uuRRR4       VP                  4        # VP                  4        \        ^ÌR7      uuRRR4       VP                  4        #   + '       g   i     MS; i  \         dC   pTP                  4        \        R	\!        T4      /4      R3u Rp?TP                  4        # Rp?ii ; i TP                  4        R#   TP                  4        i ; i)rï   TrÜ   z`UPDATE categories SET parent_id = %s, name = %s, description = %s, sort_order = %s WHERE id = %srÞ   rL   rß   rà   rá   râ   ú	Not foundé”  Nz$DELETE FROM categories WHERE id = %s©Ústatusrã   ©r«   rÎ   r¸   r   rå   rç   rN   r6   r¹   ré   r   ræ   rÍ   Úrowcountr   rn   rê   ©Úitem_idr½   rU   r@   rÈ   rì   s   &     rF   Úcategories_idrú   !  sÙ  € ä‹9€DðÜ�tÔØ�[‰[�]Œ]˜cÜ�~‰~ Õ&Ü!×*Ò*°$Ô7×=Ð=¸2�Ø—‘ØvØ—[‘[ Ó-¨w¯{©{¸6Ó/BÀGÇKÁKÐP]ÓD^Ð`g×`kÑ`kÐlxÐz{Ó`|ð  Fð  Gôð —‘ÐDÀwÀjÔQØ—l‘l“n�ßØ—M‘M”OÜ" G¨[Ð#9Ó:¸CÐ?÷ ‰]ð0 	�
‰
�ð —‘”Ü˜s“|÷ ‰]ð0 	�
‰
�ð �K‰KÐ>ÀÀ
ÔKØ�|‰|˜qÔ Ø—‘”Ü ¨Ð5Ó6¸Ð;÷# ‰]ð0 	�
‰
�ð �K‰KŒMÜ 3Ô'÷' ‰]ð0 	�
‰
�÷1 �]ûô( ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úð) ð0 	�
‰
Žøˆ�
‰
�úó„   Œ#G: ¯4G'Á$BG'Ã&G'Ä
G: ÄG'Ä9
G: ÅAG'Æ
G: Æ1G'Ç
G: Ç'G7	Ç2G: Ç6I Ç7G: Ç:IÈ'IÈ,IÈ-I ÉIÉI ÉI/c                 ó®   € Vf   R# V P                  R\        V4      34       V P                  4       p\        T;'       d    VP	                  R4      4      # )NFzKSELECT COALESCE(slot_unusable, 0) AS u FROM storage_locations WHERE id = %sÚu)rN   rP   r¹   ra   r6   )rU   Úlocation_idrÈ   s   && rF   Ú_storage_location_slot_unusablerÿ   A  sM   € ØÒÙØ‡K�KØUÜ	ˆ[Ó	Ðôð �,‰,‹.€CÜ�×$Ð$˜Ÿ™ ›Ó%Ð%re   z/api/storage-locationsc                  óÜ  € \        4       p  \        V 4       V P                  4       ;_uu_ 4       p\        P                  R 8X  dG   VP                  R4       VP                  4       p\        V4      uuRRR4       V P                  4        # \        P                  ! RR7      ;'       g    / pVP                  RVP                  R4      VP                  RR4      VP                  R	R4      VP                  R
^ 4      34       VP                  RVP                  34       V P                  4        \        VP                  4       4      ^É3uuRRR4       V P                  4        #   + '       g   i     MS; i  \         dC   pT P                  4        \        R\!        T4      /4      R3u Rp?T P                  4        # Rp?ii ; i T P                  4        R#   T P                  4        i ; i)rÕ   zsSELECT id, parent_id, name, description, sort_order, slot_unusable FROM storage_locations ORDER BY sort_order, nameNTrÜ   ú`INSERT INTO storage_locations (parent_id, name, description, sort_order) VALUES (%s, %s, %s, %s)rÞ   rL   r,   rß   rà   ú-SELECT * FROM storage_locations WHERE id = %srâ   rã   rä   rë   s        rF   Ústorage_locations_rootr  L  sx  € ä‹9€DðÜ�tÔØ�[‰[�]Œ]˜cÜ�~‰~ Ô&Ø—‘ð Jôð —|‘|“~�Ü˜t“}÷ ‰]ð& 	�
‰
�ô ×&Ò&¨dÔ3×9Ð9°rˆGØ�K‰KØrØ—‘˜[Ó)¨7¯;©;°v¸rÓ+BÀGÇKÁKÐP]Ð_aÓDbÐdk×doÑdoÐp|Ð~ó  eAð  Bôð �K‰KÐGÈ#Ï-É-ÐIYÔZØ�K‰KŒMÜ˜3Ÿ<™<›>Ó*¨CÐ/÷ ‰]ð& 	�
‰
�÷' �]ûô ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úð ð& 	�
‰
Žøˆ�
‰
�úrî   ÚBÚprefixÚ
num_digitsrÄ   ÚcolsÚBAÚBCc           	      óX  € \         V,          pVR ,          p\        P                  ! R\        P                  ! V4       R24      p^ pV  F]  pT;'       g    RP	                  4       pVP                  V4      pV'       g   K8  \        V\        VP                  ^4      ^
4      4      pK_  	  V# )r  Ú^z(\d+)-r,   )	Ú_BATCH_BIN_SPECSÚreÚcompileÚescaper�   r¦   ÚmaxrP   Úgroup)	rA   Úbin_typeÚspecr  ÚpatternÚmax_nrŸ   rL   Úms	   &&       rF   Ú_batch_bin_max_serialr  n  sŽ   € Ü˜HÕ%€DØ�(�^€FÜ�jŠj˜AœbŸiši¨Ó/Ð0°Ð7Ó8€GØ€EÛˆØ—	�	�r× Ñ Ó"ˆØ�M‰M˜$Óˆß‰1Ü˜œs 1§7¡7¨1£:¨rÓ2Ó3ŠEñ	 ð
 €Lre   c                 óÈ   € . p\        V4       FP  p\        \        R 4      V,           4      p\        ^V^,           4       F  pVP                  V  RV V 24       K  	  KR  	  V# )ÚAÚ-)ÚrangeÚchrÚordr:   )Úbin_baserÄ   r  r¾   rX   Ú
row_letterrÆ   s   &&&    rF   Ú_batch_bin_slot_namesr   {  s^   € Ø
€CÜ�4Ž[ˆÜœ˜S› A�Ó&ˆ
Ü�q˜$ �(Ö#ˆAØ�J‰J˜(˜ 1 Z L°°Ð4Ö5ó $ñ ð €Jre   z!/api/storage-locations/batch-binsc                 óB  € \        4       p  \        V 4       \        P                  ! RR7      ;'       g    / pVP	                  R4      ;'       g    RP                  4       P                  4       p \        VP	                  R^4      4      pT\        9  d    \        RR	/4      R3T P                  4        # T^8  g   T^28”  d    \        RR
/4      R3T P                  4        # \        T,          pTR,          pTR,          pTR,          pTR,          pT P                  4       ;_uu_ 4       p	T	P                  R4       T	P                  4       p
T
 Uu0 uF+  q»P	                  R4      ;'       g    RP                  4       kK-  	  pp\!        YÂ4      ^,           p. p. p\#        T4       Fß  pTT,           p\%        T4      p\'        T4      T8”  d5   \        RRT RT RT 2/4      R3u uuRRR4       T P                  4        # TTP)                  T4      ,           pTP+                  T4       \-        TYx4       FK  pTT9   d1   \        RRT 2/4      R3u u uuRRR4       T P                  4        # TP+                  T4       KM  	  Ká  	  \/        4       pT FI  pTT9   d/   \        RRT 2/4      R3u uuRRR4       T P                  4        # TP1                  T4       KK  	  T Uu. uF	  pRTR^ 3NK  	  ppT	P3                  RT4       T P5                  4        \        R\'        T4      RTRTRYx,          /4      ^É3uuRRR4       T P                  4        #   \        \        3 d#    \        RR/4      R3u T P                  4        # i ; iu upi u upi   + '       g   i     MS; i  \6         dC   pT P9                  4        \        R\%        T4      /4      R3u Rp?T P                  4        # Rp?ii ; i T P                  4        R#   T P                  4        i ; i)u]   Create one or more standard bins (grid of pocket locations). Types: B 4Ã—6, BA 3Ã—6, BC 5Ã—7.TrÜ   r  r,   Úcountrâ   zcount must be an integeré�  z#bin_type must be "B", "BA", or "BC"zcount must be between 1 and 50r  r  rÄ   r  z"SELECT name FROM storage_locationsrL   zNext bin number z	 exceeds z digit width for type NzLocation already exists: zInternal duplicate slot name: r  ÚcreatedÚbinsÚslots_per_binrã   )r«   rÎ   r   rç   r6   r�   ÚupperrP   Ú	TypeErrorÚ
ValueErrorr   ræ   r  r¸   rN   rO   r  r  rê   rQ   Úzfillr:   r   r—   r�   rT   rÍ   rn   ré   )r½   r@   r  r"  r  r  r  rÄ   r  rU   rW   rX   Úexisting_namesÚstart_serialÚnames_to_insertÚ	bin_basesr[   ÚserialÚ
serial_strr  ÚslotÚ	dup_checkÚnrL   Úinsert_rowsrì   s                             rF   Ústorage_locations_batch_binsr5  „  sá  € ô ‹9€DðEÜ�tÔÜ×"Ò"¨$Ô/×5Ð5°2ˆØ—K‘K 
Ó+×1Ð1¨r×8Ñ8Ó:×@Ñ@ÓBˆð	GÜ˜Ÿ™ G¨QÓ/Ó0ˆEð Ô+Ô+Ü˜GÐ%JÐKÓLÈcÐQðv 	�
‰
�ðu �1Œ9˜ œ
Ü˜GÐ%EÐFÓGÈÐLðr 	�
‰
�ôo   Õ)ˆØ�h•ˆØ˜,Õ'ˆ
Ø�F�|ˆØ�F�|ˆà�[‰[�]Œ]˜cØ�K‰KÐ<Ô=ØŸL™L›NˆMÙERÓSÁ]ÀŸu™u V›}×2Ð2°×9Ñ9Ö;Á]ˆNÐSä0°ÓJÈQÕNˆLØ ˆOØˆIÜ˜5–\�Ø%¨Õ)�Ü  ›[�
Ü�z“? ZÔ/Ü"Ø Ð$4°V°H¸IÀjÀ\ÐQgÐhpÐgqÐ"rÐsóàðñ ÷ ‰]ðb 	�
‰
�ðE " J×$4Ñ$4°ZÓ$@Õ@�Ø× Ñ  Ô*Ü1°(¸DÖG�DØ˜~Ô-Ü&¨Ð3LÈTÈFÐ1SÐ'TÓUÐWZÐZÓZ÷' ‰]ðb 	�
‰
�ð; $×*Ñ*¨4Ö0ó Hñ "ô ›ˆIÛ$�Ø˜	”>Ü" GÐ/MÈaÈSÐ-QÐ#RÓSÐUXÐXÑX÷3 ‰]ðb 	�
‰
�ð/ —‘˜aÖ ñ %ñ
 <KÓK¹?°4˜D $¨¨AÓ.¹?ˆKÐKØ�O‰OØrØôð �K‰KŒMäà!¤3 Ó#7Ø" HØ 	Ø'¨­ð	óð ð
÷E ‰]ðb 	�
‰
�øô œ:Ð&ô 	GÜ˜GÐ%?Ð@ÓAÀ3ÐFÑFð| 	�
‰
�ð	Güò" Tùò2 L÷9 �]ûôZ ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úð[ ðb 	�
‰
Žøˆ�
‰
�ús×   ŒAN) ÁN) Á0M ÂN) Â5N) Ã"A	N) Ä+&NÅNÅ-NÆA#NÇ%
N) È ANÉ
N) É/ANÊ1
N) ËNË%NË4ANÌ;
N) Í N	Í6N) ÎN	Î	N) Î
NÎN&	Î!N) Î%P Î&N) Î)O6Î4'O1ÏO6ÏP Ï1O6Ï6P ÐPz$/api/storage-locations/<int:item_id>c                 óä  € \        4       p \        V4       VP                  4       ;_uu_ 4       p\        P                  R 8X  Ed   \        P
                  ! RR7      ;'       g    / pVP                  RVP                  R4      VP                  R4      VP                  R4      VP                  R^ 4      V 34       VP                  RV 34       VP                  4       pV'       g:   VP                  4        \        R	R
/4      R3uuRRR4       VP                  4        # VP                  4        \        V4      uuRRR4       VP                  4        # VP                  RV 34       VP                  ^ 8X  d:   VP                  4        \        R	R
/4      R3uuRRR4       VP                  4        # VP                  4        \        ^ÌR7      uuRRR4       VP                  4        #   + '       g   i     MS; i  \         dC   pTP                  4        \        R	\!        T4      /4      R3u Rp?TP                  4        # Rp?ii ; i TP                  4        R#   TP                  4        i ; i)rï   TrÜ   zgUPDATE storage_locations SET parent_id = %s, name = %s, description = %s, sort_order = %s WHERE id = %srÞ   rL   rß   rà   r  râ   rò   ró   Nz+DELETE FROM storage_locations WHERE id = %srô   rã   rö   rø   s   &     rF   Ústorage_locations_idr7  Ð  sÙ  € ä‹9€DðÜ�tÔØ�[‰[�]Œ]˜cÜ�~‰~ Õ&Ü!×*Ò*°$Ô7×=Ð=¸2�Ø—‘Ø}Ø—[‘[ Ó-¨w¯{©{¸6Ó/BÀGÇKÁKÐP]ÓD^Ð`g×`kÑ`kÐlxÐz{Ó`|ð  Fð  Gôð —‘ÐKÈgÈZÔXØ—l‘l“n�ßØ—M‘M”OÜ" G¨[Ð#9Ó:¸CÐ?÷ ‰]ð0 	�
‰
�ð —‘”Ü˜s“|÷ ‰]ð0 	�
‰
�ð �K‰KÐEÈÀzÔRØ�|‰|˜qÔ Ø—‘”Ü ¨Ð5Ó6¸Ð;÷# ‰]ð0 	�
‰
�ð �K‰KŒMÜ 3Ô'÷' ‰]ð0 	�
‰
�÷1 �]ûô( ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úð) ð0 	�
‰
Žøˆ�
‰
�úrû   z2/api/storage-locations/<int:item_id>/slot-unusableÚPATCHc                ó|  € \        4       p \        V4       \        P                  ! RR7      ;'       g    / pRV9  d    \	        RR/4      R3VP                  4        # \        VP                  R4      4      pVP                  4       ;_uu_ 4       pVP                  RV 34       VP                  4       '       g*   \	        RR/4      R	3uuR
R
R
4       VP                  4        # V'       dS   VP                  RV 34       VP                  4       '       d*   \	        RR/4      R3uuR
R
R
4       VP                  4        # TP                  RV'       d   ^M^ V 34       VP                  RV 34       VP                  4       pVP                  4        \	        V4      uuR
R
R
4       VP                  4        #   + '       g   i     MS; i  \         dC   pTP                  4        \	        R\        T4      /4      R3u R
p?TP                  4        # R
p?ii ; i TP                  4        R
#   TP                  4        i ; i)z>Mark a bin pocket unusable (empty slots only) or usable again.TrÜ   Úslot_unusablerâ   zslot_unusable requiredr#  ú.SELECT id FROM storage_locations WHERE id = %srò   ró   Nú;SELECT id FROM parts WHERE storage_location_id = %s LIMIT 1z4Cannot mark unusable while a part occupies this slotz=UPDATE storage_locations SET slot_unusable = %s WHERE id = %sr  rã   )r«   rÎ   r   rç   r   ræ   ra   r6   r¸   rN   r¹   rÍ   rn   ré   rê   )rù   r½   r@   ÚwantrU   rÈ   rì   s   &      rF   Ú$storage_location_slot_unusable_patchr>  ð  s¿  € ô ‹9€DðÜ�tÔÜ×"Ò"¨$Ô/×5Ð5°2ˆØ 'Ô)Ü˜GÐ%=Ð>Ó?ÀÐDð2 	�
‰
�ô1 �G—K‘K Ó0Ó1ˆØ�[‰[�]Œ]˜cØ�K‰KÐHÈ7È*ÔUØ—<‘<—>’>Ü ¨Ð5Ó6¸Ð;÷ ‰]ð. 	�
‰
�÷' Ø—‘ØQØ�Jôð —<‘<—>’>Ü" GÐ-cÐ#dÓeÐgjÐj÷ ‰]ð. 	�
‰
�ð �K‰KØOß‘  7Ð+ôð �K‰KÐGÈ'ÈÔTØ—,‘,“.ˆCØ�K‰KŒMÜ˜3“<÷% ‰]ð. 	�
‰
�÷/ �]ûô& ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úð' ð. 	�
‰
Žøˆ�
‰
�ús…   ŒAG Á2G Â8F3Ã
G Ã#F3Ã+(F3ÄF3Ä"
G Ä=F3ÅAF3Æ
G Æ3G	Æ>G ÇH) ÇG ÇHÇ'HÇ8HÇ9H) ÈHÈH) È)H;z/api/footprintsc            	      óL  € \        4       p  \        V 4       V P                  4       ;_uu_ 4       p\        P                  P                  R 4      ;'       g    RP                  4       p \        \        P                  P                  R^d4      4      p\        ^\        VR4      4      pV'       d   VP                  RRV R2W" R2V34       MVP                  RV34       \        VP                  4       4      uuRRR4       V P                  4        #   \        \        3 d    ^dp L–i ; i  + '       g   i     MC; i  \          d3   p\        R\#        T4      /4      R3u Rp?T P                  4        # Rp?ii ; i T P                  4        R#   T P                  4        i ; i)	Úqr,   Úlimitrã   aÓ  
                    SELECT id, name, sort_order, is_active
                    FROM footprints
                    WHERE is_active = 1
                      AND name LIKE %s
                    ORDER BY
                      CASE WHEN LOWER(name) = LOWER(%s) THEN 0 ELSE 1 END,
                      CASE WHEN LOWER(name) LIKE LOWER(%s) THEN 0 ELSE 1 END,
                      sort_order,
                      name
                    LIMIT %s
                    Ú%zç
                    SELECT id, name, sort_order, is_active
                    FROM footprints
                    WHERE is_active = 1
                    ORDER BY sort_order, name
                    LIMIT %s
                    Nrâ   )r«   rÎ   r¸   r   Úargsr6   r�   rP   r(  r)  r  ÚminrN   r   rO   ræ   rn   rê   )r½   rU   r@  rA  rì   s        rF   Úfootprints_rootrE    s\  € ä‹9€Dð(Ü�tÔØ�[‰[�]Œ]˜cÜ—‘×!Ñ! #Ó&×,Ð,¨"×3Ñ3Ó5ˆAðÜœGŸL™L×,Ñ,¨W°cÓ:Ó;�ô ˜œ3˜u c›?Ó+ˆEßØ—‘ðð ˜˜˜1�X˜q C q '¨5Ð1õð  —‘ðð �Hô	ô ˜3Ÿ<™<›>Ó*÷E ‰]ðL 	�
‰
�øôE œzÐ*ô Ø’ðú÷	 �]ûôF ô /Ü˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð/úðG ðL 	�
‰
Žøˆ�
‰
�úsw   Œ#D> ¯8D+Á()DÂA&D+Ã7
D> ÄD(Ä%D+Ä'D(Ä(D+Ä+D;	Ä6D> Ä:F Ä;D> Ä>E;Å	E6Å E;Å!F Å6E;Å;F ÆF#c                 óä   € T;'       g    R P                  4       pV'       g   R# V P                  RV34       V P                  4       pV'       d!   VP                  R4      '       d
   VR,          # V# )r,   NzASELECT name FROM footprints WHERE LOWER(name) = LOWER(%s) LIMIT 1rL   )r�   rN   r¹   r6   )rU   Ú	raw_valuerŸ   Úhits   &&  rF   Ú_normalize_footprintrI  B  sX   € Ø�?ˆ?˜×
!Ñ
!Ó
#€CßÙØ‡K�KÐSÐVYÐU[Ô\Ø
�,‰,‹.€Cß
ˆs�w‰w�v�ŠØ�6�{ÐØ€Jre   c                ó`  €  \        V4      pT P                  R4       T P	                  4       pT Uu0 uF  qDR,          kK  	  ppY%9  d   . # / pT F>  pTR,          pTP                  R4      pY†9  d   . Yh&   Yh,          P                  T4       K@  	  . p	T.p
\        4       pT
'       dg   T
P                  4       pY{9   d   K   TP                  T4       T	P                  T4       TP                  TR4       F  pT
P                  T4       K  	  Kn  T	#   \        \        3 d    . u # i ; iu upi )zOIDs of root category and all descendants (empty if root_id is missing from DB).z$SELECT id, parent_id FROM categoriesÚidrÞ   r©   )
rP   r(  r)  rN   rO   r6   r:   r—   Úpopr�   )rU   Úroot_idÚridrÄ   rX   ÚknownÚchildrenÚcidÚpidr¾   Ústackr’   Úchs   &&           rF   Ú!_category_self_and_descendant_idsrU  M  s  € ðÜ�'‹lˆð ‡K�KÐ6Ô7Ø�<‰<‹>€DÙ"Ó#™d˜ˆt�WˆW™d€EÐ#Ø
ÔØˆ	Ø€HÛˆØ��gˆØ�e‰e�KÓ ˆØÔØˆH‰MØ�×Ñ˜SÖ!ñ ð €CØˆE€EÜ‹5€Dß
Ø�i‰i‹kˆØŒ;ÙØ�‰�ŒØ�
‰
�3ŒØ—,‘,˜s BÖ'ˆBØ�L‰L˜Öó (à€Jøô3 ”zÐ"ô ØŠ	ðüò $s   ‚D ²D+ÄD(Ä'D(z/api/parts/stock-valuec                 ó:  € \        4       p  \        V 4       V P                  4       ;_uu_ 4       pVP                  R4       VP	                  4       pV'       d   VP                  R4      M^ pVf   ^ p\        R\        V4      /4      uuRRR4       V P                  4        #   + '       g   i     MC; i  \         d3   p\        R\        T4      /4      R3u Rp?T P                  4        # Rp?ii ; i T P                  4        R#   T P                  4        i ; i)ua   Aggregate inventory value: sum of (quantity + overstock_quantity) Ã— average_price for all parts.zuSELECT COALESCE(SUM((quantity + COALESCE(overstock_quantity, 0)) * average_price), 0) AS total_stock_value FROM partsÚtotal_stock_valueNÚtotalStockValuerâ   rã   )r«   rÎ   r¸   rN   r¹   r6   r   Úfloatræ   rn   rê   )r½   rU   rÈ   rŸ   rì   s        rF   Úparts_stock_valuerZ  m  sÚ   € ô ‹9€DðÜ�tÔØ�[‰[�]Œ]˜cØ�K‰Kð Hôð —,‘,“.ˆCß25�#—'‘'Ð-Ô.¸1ˆCØŠ{Ø�ÜÐ-¬u°S«zÐ:Ó;÷ ‰]ð 	�
‰
�÷ �]ûô ô /Ü˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð/úð ð 	�
‰
Žøˆ�
‰
�úsS   Œ#B5 ¯AB"Â
B5 Â"B2	Â-B5 Â1D Â2B5 Â5C2Ã C-ÃC2ÃD Ã-C2Ã2D ÄDz
/api/partsc                  ó²  € \        4       p  \        V 4       V P                  4       ;_uu_ 4       p\        P                  R 8X  Edÿ   \        P
                  P                  R4      p\        P
                  P                  R4      p\        P
                  P                  R4      p\        P
                  P                  R4      pRp. pT;'       g    RP                  4       P                  4       pVR8X  d   VR,          pMmV'       df   \        W4      p	V	'       g   VR	,          pMHVR
RP                  R.\        V	4      ,          4      ,           R,           ,          pVP                  V	4       V'       d   VR,          pVP                  V4       V'       d   VR,          pVP                  WD R2.4       V'       d#   VR,          pRV R2p
VP                  WªWª.4       VR,          pVP                  Wg4       \        VP!                  4        Uu. uF  p\#        V4      NK  	  up4      uuRRR4       V P%                  4        # \        P&                  ! RR7      ;'       g    / p\)        WP                  R4      4      pVP                  R4      pVP                  R4      pVR19   d   RpM \+        V4      p \+        VP                  R^ 4      ;'       g    ^ 4      pTeK   \3        Y4      '       d:   T P1                  4        \        RR/4      R3uuRRR4       T P%                  4        # T^ 8  d:   T P1                  4        \        RR/4      R3uuRRR4       T P%                  4        # Tec   TP                  R T34       TP5                  4       '       g:   T P1                  4        \        RR!/4      R3uuRRR4       T P%                  4        # TP                  R"TP                  R#4      TP                  R4      TTP                  R$R4      TP                  R%R4      TP                  R&R4      TP                  R'^ 4      TTP                  R(R4      TP                  R)^ 4      TP                  R*^ 4      TP                  R+R4      TP                  R,4      TP                  R-4      TP                  R.4      T34       TP                  R/TP6                  34       T P9                  4        \        \#        TP5                  4       4      4      ^É3uuRRR4       T P%                  4        # u upi   \,        \.        3 d=    T P1                  4        \        RR/4      R3u uuRRR4       T P%                  4        # i ; i  \,        \.        3 d=    T P1                  4        \        RR/4      R3u uuRRR4       T P%                  4        # i ; i  + '       g   i     MS; i  \:         dC   pT P1                  4        \        R\=        T4      /4      R03u Rp?T P%                  4        # Rp?ii ; i T P%                  4        R#   T P%                  4        i ; i)2rÕ   Ú
categoryIdÚstorageLocationIdÚstorageLocationPrefixr@  aC  
                    SELECT p.id, p.category_id, p.storage_location_id, p.name, p.description, p.part_number,
                           p.quantity, p.overstock_location_id, p.overstock_quantity, p.unit, p.average_price, p.minimum_stock_level, p.comment, p.barcode, p.datasheet_url, p.datasheet_file_path, p.manufacturer, p.footprint,
                           p.created_at, p.updated_at, c.name AS category_name, s.name AS storage_location_name, so.name AS overstock_location_name,
                           pi.url AS primary_image_url, pi.file_path AS primary_image_file_path,
                           pi2.url AS secondary_image_url, pi2.file_path AS secondary_image_file_path
                    FROM parts p
                    LEFT JOIN categories c ON p.category_id = c.id
                    LEFT JOIN storage_locations s ON p.storage_location_id = s.id
                    LEFT JOIN storage_locations so ON p.overstock_location_id = so.id
                    LEFT JOIN part_images pi ON pi.id = (
                        SELECT i.id
                        FROM part_images i
                        WHERE i.part_id = p.id
                        ORDER BY i.is_primary DESC, i.id
                        LIMIT 1
                    )
                    LEFT JOIN part_images pi2 ON pi2.id = (
                        SELECT i2.id
                        FROM part_images i2
                        WHERE i2.part_id = p.id
                        ORDER BY i2.is_primary DESC, i2.id
                        LIMIT 1 OFFSET 1
                    )
                    WHERE 1=1
                r,   Ú
unassignedú AND p.category_id IS NULLú AND 1=0ú AND p.category_id IN (Ú,ú%sÚ)ú AND p.storage_location_id = %sú$ AND (s.name = %s OR s.name LIKE %s)ú-%z\ AND (p.name LIKE %s OR p.part_number LIKE %s OR p.description LIKE %s OR p.barcode LIKE %s)rB  z ORDER BY p.nameNTrÜ   Ú	footprintÚstorage_location_idÚoverstock_location_idrâ   ú0overstock_location_id must be an integer or nullr#  Úoverstock_quantityú1overstock_quantity must be a non-negative integerz4Cannot assign part to a storage slot marked unusabler;  úOverstock location not foundaw  
                INSERT INTO parts
                (category_id, storage_location_id, overstock_location_id, name, description, part_number, quantity, overstock_quantity, unit, average_price, minimum_stock_level, comment, barcode, datasheet_url, manufacturer, footprint)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                Úcategory_idrL   rß   Úpart_numberÚquantityÚunitÚaverage_priceÚminimum_stock_levelÚcommentÚbarcodeÚdatasheet_urlÚmanufacturerú!SELECT * FROM parts WHERE id = %srã   ©r,   N)r«   rÎ   r¸   r   rå   rC  r6   r�   ÚlowerrU  r…   rQ   Úextendr:   rN   r   rO   rÔ   ræ   rç   rI  rP   r(  r)  ré   rÿ   r¹   rè   rÍ   rn   rê   )r½   rU   rp  rj  Ústorage_location_prefixr@  ÚsqlÚparamsÚcat_keyÚcat_idsÚlikerX   r@   ri  Únew_locrk  rm  rì   s                     rF   Ú
parts_rootr…  ‚  sZ  € ä‹9€DðwÜ�tÔØ�[‰[�]Œ]˜cÜ�~‰~ Õ&Ü%Ÿl™l×.Ñ.¨|Ó<�Ü&-§l¡l×&6Ñ&6Ð7JÓ&KÐ#Ü*1¯,©,×*:Ñ*:Ð;RÓ*SÐ'Ü—L‘L×$Ñ$ SÓ)�ð�ð4 �Ø&×,Ð,¨"×3Ñ3Ó5×;Ñ;Ó=�Ø˜lÔ*ØÐ7Õ7‘Cß Ü?ÀÓQ�Gß"Ø˜zÕ)™àÐ8¸3¿8¹8ÀTÀFÌSÐQXË\ÕDYÓ;ZÕZÐ]`Õ`Õ`˜ØŸ™ gÔ.ß&ØÐ<Õ<�CØ—M‘MÐ"5Ô6ß*ØÐAÕA�CØ—M‘MÐ#:Ð>WÐWYÐ<ZÐ"[Ô\ßØÐyÕy�CØ˜q˜c ˜8�DØ—M‘M 4¨tÐ":Ô;ØÐ)Õ)�Ø—‘˜CÔ(Ü°S·\±\´^ÓD±^°¤¨¦±^ÑDÓE÷o ‰]ðj 	�
‰
�ôy ×&Ò&¨dÔ3×9Ð9°rˆGÜ,¨S·+±+¸kÓ2JÓKˆIØ—k‘kÐ"7Ó8ˆGØ$+§K¡KÐ0GÓ$HÐ!Ø$¨
Ô2Ø(,Ñ%ðgÜ,/Ð0EÓ,FÐ)ðdÜ%(¨¯©Ð5IÈ1Ó)M×)RÐ)RÐQRÓ%SÐ"ð Ò"Ô'FÀs×'TÒ'TØ—‘”Ü Ð)_Ð`ÓaÐcfÐf÷Y ‰]ðj 	�
‰
�ðQ " AÔ%Ø—‘”Ü Ð)\Ð]Ó^Ð`cÐc÷_ ‰]ðj 	�
‰
�ðK %Ò0Ø—‘ÐLÐOdÐNfÔgØ—|‘|—~’~Ø—M‘M”OÜ" GÐ-KÐ#LÓMÈsÐR÷i ‰]ðj 	�
‰
�ðA �K‰Kðð —K‘K Ó.Ø—K‘KÐ 5Ó6Ø)Ø—K‘K ¨Ó+Ø—K‘K ¨rÓ2Ø—K‘K ¨rÓ2Ø—K‘K 
¨AÓ.Ø&Ø—K‘K ¨Ó+Ø—K‘K °Ó3Ø—K‘KÐ 5°qÓ9Ø—K‘K 	¨2Ó.Ø—K‘K 	Ó*Ø—K‘K Ó0Ø—K‘K Ó/Øð!ôð2 �K‰KÐ;¸c¿m¹mÐ=MÔNØ�K‰KŒMÜœ8 C§L¡L£NÓ3Ó4°cÐ9÷a ‰]ðj 	�
‰
�ùò}  Eøô "¤:Ð.ô gØ—M‘M”OÜ" GÐ-_Ð#`ÓaÐcfÐfÑf÷I ‰]ðj 	�
‰
�ðggûô
 œzÐ*ô dØ—‘”Ü Ð)\Ð]Ó^Ð`cÐcÑc÷S ‰]ðj 	�
‰
�ð]dú÷O �]ûôb ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úðc ðj 	�
‰
Žøˆ�
‰
�ús  Œ#W! ¯BWÃ7WÄA,WÅ4!WÆ%WÆ<AWÈT)È#WÈ)
W! ÉWÉ"A	WÊ,T.Ê8U>ËU>Ë3WÌ
W! Ì+%WÍ
W! Í+,WÎWÎ6
W! ÏD=WÔ
W! Ô)WÔ.0U;ÕWÕ
W! Õ:U;Õ;WÕ>0WÖ.WÖ/
W! ×
W×W×W	×W! ×Y ×W! ×!X.×,'X)ØX.ØY Ø)X.Ø.Y ÙYz$/api/parts/by-barcode/<path:barcode>c                 óD  € \        4       p VP                  4       ;_uu_ 4       pVP                  R V 34       VP                  4       pV'       g*   \	        RR/4      R3uuRRR4       VP                  4        # \	        RVR,          /4      uuRRR4       VP                  4        #   + '       g   i     MC; i  \         d3   p\	        R\        T4      /4      R3u Rp?TP                  4        # Rp?ii ; i TP                  4        R#   TP                  4        i ; i)z/SELECT id FROM parts WHERE barcode = %s LIMIT 1râ   rò   ró   NrK  rã   )r«   r¸   rN   r¹   r   ræ   rn   rê   )rw  r½   rU   rÈ   rì   s   &    rF   Úparts_by_barcoder‡  ÿ  sØ   € ä‹9€Dð
Ø�[‰[�]Œ]˜cØ�K‰KÐIÈGÈ:ÔVØ—,‘,“.ˆCßÜ ¨Ð5Ó6¸Ð;÷	 ‰]ð 	�
‰
�ô	 ˜D # d¥)Ð,Ó-÷ ‰]ð 	�
‰
�÷ �]ûô ô /Ü˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð/úð ð 	�
‰
Žøˆ�
‰
�ús^   ŒB: ¤:B'Á
B: Á9B'Â
B: Â'B7	Â2B: Â6D Â7B: Â:C7ÃC2ÃC7ÃD Ã2C7Ã7D ÄDz/api/parts/exportc                  ó  € \         P                  P                  R 4      R8w  d   \        RR/4      R3# \	        4       p  V P                  4       ;_uu_ 4       p\         P                  P                  R4      p\         P                  P                  R4      p\         P                  P                  R4      p\         P                  P                  R4      pR	p. pT;'       g    R
P                  4       P                  4       pVR8X  d   VR,          pMmV'       df   \        W4      p	V	'       g   VR,          pMHVRRP                  R.\        V	4      ,          4      ,           R,           ,          pVP                  V	4       V'       d   VR,          pVP                  V4       V'       d   VR,          pVP                  WD R2.4       V'       d"   VR,          pRV R2p
VP                  Wª.4       VP                  Wg4       VP                  4       pRRR4       \        P                   ! 4       p\"        P$                  ! VRR7      pVP'                  . R/O4       X EF  pVP'                  VP                  R4      VP                  R4      VP                  R4      VP                  R4      VP                  R4      VP                  R4      VP                  R 4      VP                  R!4      VP                  R"4      VP                  R#4      VP                  R$4      VP                  R%4      VP                  R&4      VP                  R'4      VP                  R(4      VP                  R)4      .4       EK  	  \)        VP+                  4       R*R+R,/R-7      V P-                  4        #   + '       g   i     EL›; i  \.         d3   p\        R\1        T4      /4      R.3u Rp?T P-                  4        # Rp?ii ; i  T P-                  4        i ; i)0ÚformatÚcsvrâ   zformat=csv requiredr#  r\  r]  r^  r@  aj  
                SELECT p.part_number, p.name, p.barcode, p.quantity, p.overstock_quantity, p.unit, p.average_price, p.minimum_stock_level, p.comment, p.description, p.datasheet_url, p.manufacturer, p.footprint,
                       c.name AS category_name, s.name AS storage_location_name, so.name AS overstock_location_name
                FROM parts p
                LEFT JOIN categories c ON p.category_id = c.id
                LEFT JOIN storage_locations s ON p.storage_location_id = s.id
                LEFT JOIN storage_locations so ON p.overstock_location_id = so.id
                WHERE 1=1
            r,   r_  r`  ra  rb  rc  rd  re  rf  rg  rh  z. AND (p.name LIKE %s OR p.part_number LIKE %s)rB  Nz
)Úlineterminatorrq  rL   rw  rr  rm  rs  rt  ru  rv  rß   rx  ry  ri  Úcategory_nameÚstorage_location_nameÚoverstock_location_nameztext/csvúContent-Dispositionz%attachment; filename=parts-export.csv©Úmimetyper&   rã   )rq  rL   rw  rr  rm  rs  rt  ru  rv  rß   rx  ry  ri  rŒ  r�  rŽ  )r   rC  r6   r   r«   r¸   r�   r|  rU  r…   rQ   r}  r:   rN   rO   r³   r´   rŠ  ÚwriterÚwriterowr   r¼   ræ   rn   rê   )r½   rU   rp  rj  r~  r@  r  r€  r�  r‚  rƒ  rÄ   r¾   r’  rX   rì   s                   rF   Úparts_exportr”    s8  € ä‡|�|×Ñ˜Ó! UÔ*Ü˜Ð!6Ð7Ó8¸#Ð=Ð=Ü‹9€DðYØ�[‰[�]Œ]˜cÜ!Ÿ,™,×*Ñ*¨<Ó8ˆKÜ")§,¡,×"2Ñ"2Ð3FÓ"GÐÜ&-§l¡l×&6Ñ&6Ð7NÓ&OÐ#Ü—‘× Ñ  Ó%ˆAðˆCð ˆFØ"×(Ð( b×/Ñ/Ó1×7Ñ7Ó9ˆGØ˜,Ô&ØÐ3Õ3‘ßÜ;¸CÓM�ßØ˜:Õ%‘CàÐ4°s·x±xÀÀÌÈWËÕ@UÓ7VÕVÐY\Õ\Õ\�CØ—M‘M 'Ô*ß"ØÐ8Õ8�Ø—‘Ð1Ô2ß&ØÐ=Õ=�Ø—‘Ð6Ð:SÐSUÐ8VÐWÔXßØÐGÕG�Ø˜1˜#˜Q�x�Ø—‘˜t˜lÔ+Ø�K‰K˜Ô$Ø—<‘<“>ˆD÷I ôJ �kŠk‹mˆÜ—’˜C°Ô7ˆØ�‰òô	
ô( ˆAØ�O‰Oà—E‘E˜-Ó(Ø—E‘E˜&“MØ—E‘E˜)Ó$Ø—E‘E˜*Ó%Ø—E‘EÐ.Ó/Ø—E‘E˜&“MØ—E‘E˜/Ó*Ø—E‘EÐ/Ó0Ø—E‘E˜)Ó$Ø—E‘E˜-Ó(Ø—E‘E˜/Ó*Ø—E‘E˜.Ó)Ø—E‘E˜+Ó&Ø—E‘E˜/Ó*Ø—E‘EÐ1Ó2Ø—E‘EÐ3Ó4ð!÷ñ ô* Ø�L‰L‹NØØ*Ð,SÐTô
ð 	�
‰
�÷q �]ˆ]ûôj ô /Ü˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð/ûð 	�
‰
�úsc   ¿N6 ÁCN"ÄA,N"Æ!N"Æ(%N"ÇAN"ÈFN6 Î"N3	Î-	N6 Î6O3ÏO.ÏO3ÏO6 Ï.O3Ï3O6 Ï6Pz/api/parts/importc                  ó   € \         P                  P                  R 4      p V '       g   \        RR/4      R3# V P	                  4       P                  RRR7      p\        P                  ! \        P                  ! V4      4      p\        V4      pV'       g   \        R^ R^ R	R
./4      # \        4       p^ p^ p. p VP                  4       ;_uu_ 4       p\        V^R7       EFk  w  ršV
P                  R4      ;'       g    RP                  4       pV
P                  R4      ;'       g    RP                  4       pV'       g   V'       g   Kj  V
P                  R4      ;'       g    RP                  4       ;'       g    Rp \        V
P                  R4      ;'       g    RP                  4       ;'       g    R4      p \        V
P                  R4      ;'       g    RP                  4       ;'       g    R4      pV
P                  R4      ;'       g    RP                  4       p \#        V
P                  R4      ;'       g    RP                  4       ;'       g    R4      p \        V
P                  R4      ;'       g    RP                  4       ;'       g    R4      pV
P                  R4      ;'       g    RP                  4       pV
P                  R4      ;'       g    RP                  4       pV
P                  R4      ;'       g    RP                  4       ;'       g    RpV
P                  R4      ;'       g    RP                  4       ;'       g    Rp\%        WŠP                  R4      4      pV
P                  R4      ;'       g    RP                  4       pV
P                  R4      ;'       g    RP                  4       pV
P                  R4      ;'       g    RP                  4       pRpRpRpV'       d5   VP'                  RV34       VP)                  4       pV'       d
   VR ,          pV'       d5   VP'                  R!V34       VP)                  4       pV'       d
   VR ,          pV'       d5   VP'                  R!V34       VP)                  4       p V '       d
   V R ,          p TP'                  R"Y½;'       g    R34       VP)                  4       p!V!'       d@   VP'                  R#VVVVVV\+        ^ V4      VVVVVVVVV!R ,          34       V^,          pEK6  VP'                  R$VVVVVVV\+        ^ V4      VVVVVVVV34       V^,          pEKn  	  RRR4       VP1                  4        \        RVRVR	V/4      VP3                  4        #   \          d    ^ p ELßi ; i  \          d    ^ p EL¶i ; i  \          d    ^ p ELdi ; i  \          d    ^ p EL;i ; i  \,         d$   p"TP/                  R%T	 R&T" 24        Rp"?"EK"  Rp"?"ii ; i  + '       g   i     LÂ; i  \,         dC   p#TP5                  4        \        R\7        T#4      /4      R'3u Rp#?#TP3                  4        # Rp#?#ii ; i  TP3                  4        i ; i)(Úfilerâ   úNo file uploadedr#  r)   Úignore)Úerrorsr$  Úupdatedr™  zNo data rows)Ústartrq  r,   rL   rw  Nrr  Ú0rm  rs  rt  ru  rv  rß   rx  ry  ri  rŒ  r�  rŽ  z1SELECT id FROM categories WHERE name = %s LIMIT 1rK  z8SELECT id FROM storage_locations WHERE name = %s LIMIT 1zZSELECT id FROM parts WHERE part_number = %s OR (part_number = '' AND barcode = %s) LIMIT 1a(  
                            UPDATE parts
                            SET category_id = %s, storage_location_id = %s, name = %s, description = %s,
                                overstock_location_id = %s, quantity = %s, overstock_quantity = %s, unit = %s, average_price = %s, minimum_stock_level = %s, comment = %s,
                                barcode = %s, datasheet_url = %s, manufacturer = %s, footprint = %s,
                                updated_at = CURRENT_TIMESTAMP
                            WHERE id = %s
                            a§  
                            INSERT INTO parts
                            (category_id, storage_location_id, overstock_location_id, name, description, part_number, quantity, overstock_quantity, unit, average_price, minimum_stock_level, comment, barcode, datasheet_url, manufacturer, footprint)
                            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                            zRow z: rã   )r   Úfilesr6   r   r4   r5   rŠ  Ú
DictReaderr³   r´   r;   r«   r¸   rS   r�   rP   r)  rY  rI  rN   r¹   r  rn   r:   rÍ   ræ   ré   rê   )$r–  ÚtextÚreaderrÄ   r½   r$  rš  r™  rU   r[   rÈ   rq  rL   rw  rr  rm  rs  rt  ru  rv  rß   rx  ry  ri  rŒ  Úlocation_namerŽ  rp  rj  rk  ÚcatÚlocÚover_locrY   Úrow_errrì   s$                                       rF   Úparts_importr¦  p  s°  € ä�=‰=×Ñ˜VÓ$€DßÜ˜Ð!3Ð4Ó5°sÐ:Ð:Ø�9‰9‹;×Ñ˜g¨hÐÓ7€DÜ�^Š^œBŸKšK¨Ó-Ó.€FÜ�‹<€DßÜ˜	 1 i°°H¸~Ð>NÐOÓPÐPÜ‹9€DØ€GØ€GØ€Fð{Ø�[‰[�]Œ]˜cÜ# D°×2Ð2‘�Ø"Ÿw™w }Ó5×;Ð;¸×BÑBÓD�ØŸ™ ›×-Ð-¨2×4Ñ4Ó6�ß"¯4ÙØŸ7™7 9Ó-×3Ð3°×:Ñ:Ó<×DÐDÀ�ð!Ü" C§G¡G¨JÓ$7×$>Ð$>¸3×#EÑ#EÓ#G×#NÐ#NÈ3ÓO�Hð+Ü),¨c¯g©gÐ6JÓ.K×.RÐ.RÈs×-YÑ-YÓ-[×-bÐ-bÐ_bÓ)cÐ&ð Ÿ™ ›×-Ð-¨2×4Ñ4Ó6�ð&Ü$)¨3¯7©7°?Ó+C×+JÐ+JÀs×*QÑ*QÓ*S×*ZÐ*ZÐWZÓ$[�Mð,Ü*-¨s¯w©wÐ7LÓ/M×/TÐ/TÐQT×.[Ñ.[Ó.]×.dÐ.dÐadÓ*eÐ'ð Ÿ7™7 9Ó-×3Ð3°×:Ñ:Ó<�Ø"Ÿw™w }Ó5×;Ð;¸×BÑBÓD�Ø!$§¡¨Ó!9×!?Ð!?¸R× FÑ FÓ H× PÐ PÈD�Ø #§¡¨Ó 7× =Ð =¸2×DÑDÓF×NÐNÈ$�Ü0°·g±g¸kÓ6JÓK�	Ø!$§¡¨Ó!9×!?Ð!?¸R× FÑ FÓ H�Ø!$§¡Ð)@Ó!A×!GÐ!GÀR× NÑ NÓ P�Ø+.¯7©7Ð3LÓ+M×+SÐ+SÐQS×*ZÑ*ZÓ*\Ð'à"�Ø&*Ð#Ø(,Ð%ß Ø—K‘KÐ SÐVcÐUeÔfØŸ,™,›.�CßØ&)¨$¥i˜ß Ø—K‘KÐ ZÐ]jÐ\lÔmØŸ,™,›.�CßØ.1°$­iÐ+ß*Ø—K‘KÐ ZÐ]tÐ\vÔwØ"Ÿ|™|›~�HßØ08¸µÐ-ð@9Ø—K‘KØtØ$§m m°Ð4ôð  #Ÿ|™|›~�HßØŸ™ð ð !,Ø 3Ø $Ø +Ø 5Ø (Ü # AÐ'9Ó :Ø $Ø -Ø 3Ø 'Ø 'Ø -Ø ,Ø )Ø (¨¥ð!ôð8   1�›àŸ™ð ð !,Ø 3Ø 5Ø $Ø +Ø +Ø (Ü # AÐ'9Ó :Ø $Ø -Ø 3Ø 'Ø 'Ø -Ø ,Ø )ð!ôð2   1�›ña 3÷ ðh 	�‰ŒÜ˜	 7¨I°wÀÈ&ÐQÓRð
 	�
‰
�øôc "ô !Ø “Hð!ûô "ô +Ø)*Ó&ð+ûô
 "ô &Ø$%“Mð&ûô "ô ,Ø*+Ó'ð,ûôx !ô 9Ø—M‘M D¨¨¨2¨g¨YÐ"7×8Ó8ûð9ú÷e �]ûôl ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/ûð 	�
‰
�úsÂ  Â8X Ã+XÃ<(XÄ%XÄ>XÅXÅ XÅ8XÅ<VÆVÆ1VÆ9VÇVÇ.VÇ5XÈXÈV/È<V/ÉV/ÉWÉ9WÊWÊXÊ0(XË(XÌXÌXÌ5XÍ4XÎ(XÎ+(XÏXÏ3*XÐXÐ/*XÑXÑ+*XÒ	XÒ WÒ5WÓ<WÔXÔ5WÕ	XÕ(X ÖV	ÖXÖV	ÖXÖV,	Ö(XÖ+V,	Ö,XÖ/W 	Ö<XÖ?W 	× X×W	×X×W	×X×X	×"X 	×9XØ X	ØXØX	ØX ØY(Ø&'Y#ÙY(ÙY+ Ù#Y(Ù(Y+ Ù+Y=z/api/parts/<int:part_id>c                 ó.  € \        4       p \        V4       VP                  4       ;_uu_ 4       p\        P                  R 8X  dÂ   VP                  RV 34       VP                  4       pV'       g*   \        RR/4      R3uuRRR4       VP                  4        # VP                  RV 34       VP                  4        Uu. uF  p\        V4      NK  	  upVR&   \        \        V4      4      uuRRR4       VP                  4        # \        P                  R8X  Ed¹   \        P                  ! R	R
7      ;'       g    / p\        W%P                  R4      4      pVP                  RV 34       VP                  4       pV'       g:   VP                  4        \        RR/4      R3uuRRR4       VP                  4        # VP                  R4      pVP                  R4      p	VP                  R4      p
V
R'9   d   Rp
M \        V
4      p
 \        VP                  R^ 4      ;'       g    ^ 4      pT	ev   \%        Y)4      '       de   TRJ;'       d    \        T	4      \        T4      8H  pT'       g:   TP                  4        \        RR/4      R3uuRRR4       TP                  4        # T^ 8  d:   TP                  4        \        RR/4      R3uuRRR4       TP                  4        # T
ec   TP                  RT
34       TP                  4       '       g:   TP                  4        \        RR/4      R3uuRRR4       TP                  4        # TP                  RTP                  R4      TP                  R4      TP                  R4      TP                  R4      T
TP                  R4      TP                  R^ 4      TTP                  R4      TP                  R^ 4      TP                  R^ 4      TP                  R4      TP                  R 4      TP                  R!4      TP                  R"4      TT 34       TP                  R#T 34       TP                  4       pT'       g:   TP                  4        \        RR/4      R3uuRRR4       TP                  4        # TP'                  4        \        \        T4      4      uuRRR4       TP                  4        # VP                  R$V 34       VP(                  ^ 8X  d:   VP                  4        \        RR/4      R3uuRRR4       VP                  4        # VP'                  4        \+        ^ÌR%7      uuRRR4       VP                  4        # u upi   \         \"        3 d=    TP                  4        \        RR/4      R3u uuRRR4       TP                  4        # i ; i  \         \"        3 d=    TP                  4        \        RR/4      R3u uuRRR4       TP                  4        # i ; i  + '       g   i     MS; i  \,         dC   pTP                  4        \        R\/        T4      /4      R&3u Rp?TP                  4        # Rp?ii ; i TP                  4        R#   TP                  4        i ; i)(rÕ   a×  
                    SELECT p.*, c.name AS category_name, s.name AS storage_location_name
                    , so.name AS overstock_location_name
                    FROM parts p
                    LEFT JOIN categories c ON p.category_id = c.id
                    LEFT JOIN storage_locations s ON p.storage_location_id = s.id
                    LEFT JOIN storage_locations so ON p.overstock_location_id = so.id
                    WHERE p.id = %s
                    râ   rò   ró   Nzó
                    SELECT id, file_path, original_filename, url, source, is_primary, created_at
                    FROM part_images
                    WHERE part_id = %s
                    ORDER BY is_primary DESC, id
                    Úimagesrï   TrÜ   ri  z3SELECT storage_location_id FROM parts WHERE id = %srj  rk  rl  r#  rm  rn  z2Cannot move part to a storage slot marked unusabler;  ro  aê  
                    UPDATE parts
                    SET category_id = %s, storage_location_id = %s, name = %s, description = %s,
                        overstock_location_id = %s, part_number = %s, quantity = %s, overstock_quantity = %s, unit = %s, average_price = %s, minimum_stock_level = %s,
                        comment = %s, barcode = %s, datasheet_url = %s, manufacturer = %s, footprint = %s, updated_at = CURRENT_TIMESTAMP
                    WHERE id = %s
                    rp  rL   rß   rq  rr  rs  rt  ru  rv  rw  rx  ry  rz  zDELETE FROM parts WHERE id = %srô   rã   r{  )r«   rÎ   r¸   r   rå   rN   r¹   r   ræ   rO   rÔ   rç   rI  r6   ré   rP   r(  r)  rÿ   rÍ   r÷   r   rn   rê   )Úpart_idr½   rU   ÚpartrX   r@   ri  Úexisting_rowÚold_locr„  rk  rm  Ú	same_slotrÈ   rì   s   &              rF   Úparts_idr®  ü  s•  € ä‹9€DðrÜ�tÔØ�[‰[�]Œ]˜cÜ�~‰~ Ô&Ø—‘ðð �Jôð —|‘|“~�ßÜ" G¨[Ð#9Ó:¸CÐ?÷! ‰]ð` 	�
‰
�ð —‘ðð �Jôð 8;·|±|´~Ó!F±~°!¤(¨1¦+±~Ñ!F��X‘Üœx¨›~Ó.÷7 ‰]ð` 	�
‰
�ôg �~‰~ Õ&Ü!×*Ò*°$Ô7×=Ð=¸2�Ü0°·k±kÀ+Ó6NÓO�	Ø—‘ÐQÐT[ÐS]Ô^Ø"Ÿ|™|›~�ß#Ø—M‘M”OÜ" G¨[Ð#9Ó:¸CÐ?÷I ‰]ð` 	�
‰
�ðW '×*Ñ*Ð+@ÓA�Ø!Ÿ+™+Ð&;Ó<�Ø(/¯©Ð4KÓ(LÐ%Ø(¨JÔ6Ø,0Ñ)ðkÜ03Ð4IÓ0JÐ-ðhÜ),¨W¯[©[Ð9MÈqÓ-Q×-VÐ-VÐUVÓ)WÐ&ð Ò&Ô+JÈ3×+XÒ+XØ '¨tÐ 3× TÐ T¼¸G»ÌÈGËÑ8T�Iß$ØŸ™œÜ&¨Ð1eÐ'fÓgÐilÐl÷s ‰]ð` 	�
‰
�ðm &¨Ô)Ø—M‘M”OÜ" GÐ-`Ð#aÓbÐdgÐg÷y ‰]ð` 	�
‰
�ðg )Ò4Ø—K‘KÐ PÐShÐRjÔkØŸ<™<Ÿ>š>ØŸ™œÜ&¨Ð1OÐ'PÓQÐSVÐV÷C ‰]ð` 	�
‰
�ð] —‘ðð  Ÿ™ MÓ2ØŸ™Ð$9Ó:ØŸ™ FÓ+ØŸ™ MÓ2Ø-ØŸ™ MÓ2ØŸ™ J°Ó2Ø*ØŸ™ FÓ+ØŸ™ O°QÓ7ØŸ™Ð$9¸1Ó=ØŸ™ IÓ.ØŸ™ IÓ.ØŸ™ OÓ4ØŸ™ NÓ3Ø!Øð#ôð8 —‘Ð?À'ÀÔLØ—l‘l“n�ßØ—M‘M”OÜ" G¨[Ð#9Ó:¸CÐ?÷E ‰]ð` 	�
‰
�ð —‘”Üœx¨›}Ó-÷I ‰]ð` 	�
‰
�ð �K‰KÐ9¸G¸:ÔFØ�|‰|˜qÔ Ø—‘”Ü ¨Ð5Ó6¸Ð;÷S ‰]ð` 	�
‰
�ð �K‰KŒMÜ 3Ô'÷W ‰]ð` 	�
‰
�ùòm "Gøô& &¤zÐ2ô kØŸ™œÜ&¨Ð1cÐ'dÓeÐgjÐjÑj÷_ ‰]ð` 	�
‰
�ðGkûô
 "¤:Ð.ô hØ—M‘M”OÜ" GÐ-`Ð#aÓbÐdgÐgÑg÷i ‰]ð` 	�
‰
�ð}hú÷e �]ûôX ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úðY ð` 	�
‰
Žøˆ�
‰
�úsL  Œ#X ¯A XÁ0XÁ>
X Â%XÂ>U'ÃXÃ+
X Ä3XÄ:A&XÆ 
X Æ;=XÇ9U,ÈV<È#V<È*XÉ
XÉ*XÊ
X Ê#%XË
X Ë#,XÌXÌ.
X Í	DXÑXÑ;
X Ò#XÒ9
X ÓAXÔ
X Ô1XÕ
X Õ'XÕ,0V9ÖXÖ
X Ö8V9Ö9XÖ<0X	×,X×-
X ØX	Ø	XØX	ØX ØZ ØX ØY,Ø*'Y'ÙY,ÙZ Ù'Y,Ù,Z ÚZc                 ó2   € R V  RV 2P                  RR4      # )zparts/r‹   rŠ   ©r�   )r©  Úfilenames   &&rF   Ú_image_upload_relativer²  t  s"   € Ø�G�9˜A˜h˜ZÐ(×0Ñ0°°sÓ;Ð;re   c                 ó.   € R V  R2P                  RR4      # )údatasheets/z.pdfrŠ   r‹   r°  ©r©  s   &rF   Ú_datasheet_upload_relativer¶  x  s   € Ø˜˜	 Ð&×.Ñ.¨t°SÓ9Ð9re   c                 ó.   € R V  R2P                  RR4      # )r´  z
.thumb.jpgrŠ   r‹   r°  rµ  s   &rF   Ú_datasheet_thumbnail_relativer¸  |  s   € Ø˜˜	 Ð,×4Ñ4°T¸3Ó?Ð?re   c                óP  € \         f   R# Rp \         P                  ! V 4      pVP                  ^8  d    Ve   VP                  4        R# R# VP	                  ^ 4      pVP                  \         P                  ! RR4      RR7      p\        P                  ! \        P                  P                  V4      RR7       VP                  V4        Ve   VP                  4        R# R#   \         d     Te   TP                  4        R# R# i ; i  Te   TP                  4        i i ; i)zCRender first PDF page to JPEG thumbnail. Returns True if generated.NFg      ø?)ÚmatrixÚalphaTrq   )Úfitzrl   Ú
page_countræ   Ú	load_pageÚ
get_pixmapÚMatrixri   ru   r+   rv   Úsavern   )Úpdf_pathÚ
thumb_pathÚdocÚpageÚpixs   &&   rF   Ú_generate_datasheet_thumbnailrÇ  €  sï   € ä‚|ÙØ
€CðÜ�iŠi˜Ó!ˆØ�>‰>˜AÔØð Š?Ø�I‰IŽKñ ð �}‰}˜QÓˆØ�o‰o¤T§[¢[°°cÓ%:À%ˆoÓHˆÜ
�Š”B—G‘G—O‘O JÓ/¸$Õ?Ø�‰�ÔØð Š?Ø�I‰IŽKñ øô ô ØàŠ?Ø�I‰IŽKñ ðûð Š?Ø�I‰I�Kð ús*   Ž'C& ÁA?C& Ã&DÃ1D Ä
DÄD ÄD%z"/api/parts/<int:part_id>/duplicatec                óÒ  € \         P                  ! RR7      ;'       g    / pVP                  R4      pVf   \        RR/4      R3#  \	        V4      p\        4       p\        4       p \        T4       TP                  4       ;_uu_ 4       pTP                  R	T 34       TP                  4       pT'       g*   \        RR
/4      R3uuRRR4       TP                  4        # TP                  R4      T8X  d*   \        RR/4      R3uuRRR4       TP                  4        # TP                  RT34       TP                  4       '       d*   \        RR/4      R3uuRRR4       TP                  4        # \        YR4      '       d*   \        RR/4      R3uuRRR4       TP                  4        # TP                  RTR,          TRTR,          TR,          TR,          ^ ^ TR,          TP                  R4      ;'       g    ^ TR,          TR,          RTR,          RRTR,          \        YVP                  R4      4      34       TP                   pTP                  RT 34       TP#                  4        EFâ  pTP                  R4      '       d-   TP                  RYxR,          TR,          TR ,          34       KG  TP                  R!4      '       g   K`  \%        YHR!,          4      p	T	'       g   K|  TP                  R"4      ;'       g'    \&        P(                  P+                  TR!,          4      p
\&        P(                  P-                  T
4      ^,          ;'       g8    \&        P(                  P-                  TR!,          4      ^,          ;'       g    R#p\&        P.                  ! ^4      P1                  4       pT T 2p\3        Y}4      p\&        P(                  P5                  YN4      p\&        P6                  ! \&        P(                  P9                  T4      RR$7       \:        P<                  ! YŸ4       TP                  R%Y~Y¨R,          TR ,          34       EKå  	  TP                  R&4      pT'       dÑ   \&        P(                  P5                  TT4      p\&        P(                  P?                  T4      '       dŒ   \A        T4      p\&        P(                  P5                  TT4      p\&        P6                  ! \&        P(                  P9                  T4      RR$7       \:        P<                  ! TT4       TP                  R'TT34       TP                  R(4      pT'       dÑ   \&        P(                  P5                  TT4      p\&        P(                  P?                  T4      '       dŒ   \C        T4      p\&        P(                  P5                  TT4      p\&        P6                  ! \&        P(                  P9                  T4      RR$7       \:        P<                  ! TT4       TP                  R)TT34       TP                  R*T34       TP                  4       pTP                  R+T34       TP#                  4        Uu. uF  p\E        T4      NK  	  upTR,&   RRR4       TPG                  4        \        \E        X4      4      ^É3TP                  4        #   \
        \        3 d    \        RR/4      R3u # i ; iu upi   + '       g   i     Lq; i  \H         dC   pTPK                  4        \        R\M        T4      /4      R-3u Rp?TP                  4        # Rp?ii ; i  TP                  4        i ; i).zeClone a part into another storage location (qty reset to 0); copy average_price and file attachments.TrÜ   rj  Nrâ   zstorage_location_id requiredr#  z&storage_location_id must be an integerrz  zSource part not foundró   z.Target location is the same as the source partr<  z$Target storage location is not emptyz&Target storage slot is marked unusableaÐ  
                INSERT INTO parts
                (category_id, storage_location_id, overstock_location_id, name, description, part_number,
                 quantity, overstock_quantity, unit, average_price, minimum_stock_level, comment,
                 barcode, datasheet_url, datasheet_file_path, datasheet_thumbnail_path, manufacturer, footprint)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                rp  rL   rß   rq  rs  rt  ru  rv  rx  ry  ri  zÓ
                SELECT id, file_path, original_filename, url, source, is_primary
                FROM part_images
                WHERE part_id = %s
                ORDER BY is_primary DESC, id
                ÚurlúRINSERT INTO part_images (part_id, url, source, is_primary) VALUES (%s, %s, %s, %s)ÚsourceÚ
is_primaryÚ	file_pathÚoriginal_filenamez.binrq   úoINSERT INTO part_images (part_id, file_path, original_filename, source, is_primary) VALUES (%s, %s, %s, %s, %s)Údatasheet_file_pathz7UPDATE parts SET datasheet_file_path = %s WHERE id = %sÚdatasheet_thumbnail_pathz<UPDATE parts SET datasheet_thumbnail_path = %s WHERE id = %sa0  
                SELECT p.*, c.name AS category_name, s.name AS storage_location_name
                FROM parts p
                LEFT JOIN categories c ON p.category_id = c.id
                LEFT JOIN storage_locations s ON p.storage_location_id = s.id
                WHERE p.id = %s
                zß
                SELECT id, file_path, original_filename, url, source, is_primary, created_at
                FROM part_images
                WHERE part_id = %s
                ORDER BY is_primary DESC, id
                r¨  rã   )'r   rç   r6   r   rP   r(  r)  r«   rˆ   rÎ   r¸   rN   r¹   ræ   rÿ   rI  rè   rO   r§   ri   r+   Úbasenamerš   ÚurandomÚhexr²  r…   ru   rv   ÚshutilÚcopy2r™   r¶  r¸  rÔ   rÍ   rn   ré   rê   )r©  r@   Útarget_storage_location_idr½   r�   rU   ÚsrcÚnew_idÚimgÚsrc_pathÚorigÚextÚrandÚnew_fnr�   Údst_pathÚdsÚsrc_pdfÚnew_relÚdst_pdfÚds_thumbÚ	src_thumbÚnew_thumb_relÚ	dst_thumbrª  rX   rì   s   &                          rF   Úpart_duplicateré  •  s÷  € ô ×Ò dÔ+×1Ð1¨r€GØ!(§¡Ð-BÓ!CÐØ!Ò)Ü˜Ð!?Ð@ÓAÀ3ÐFÐFðQÜ%(Ð)CÓ%DÐ"ô ‹9€DÜ'Ó)€KðEÜ�tÔØ�[‰[�]Œ]˜cØ�K‰KÐ;¸g¸ZÔHØ—,‘,“.ˆCßÜ Ð)@ÐAÓBÀCÐG÷	 ‰]ðF 	�
‰
�ð} �w‰wÐ,Ó-Ð1KÔKÜ Ð)YÐZÓ[Ð]`Ð`÷ ‰]ðF 	�
‰
�ðy �K‰KØMØ+Ð-ôð �|‰|�~Š~Ü Ð)OÐPÓQÐSVÐV÷ ‰]ðF 	�
‰
�ôm /¨s×OÒOÜ Ð)QÐRÓSÐUXÐX÷ ‰]ðF 	�
‰
�ðg �K‰Kðð ˜Õ&Ø.ØØ˜•KØ˜Õ&Ø˜Õ&ØØØ˜•KØ—G‘G˜OÓ,×1Ð1°ØÐ-Õ.Ø˜	•NØØ˜Õ(ØØØ˜Õ'Ü(¨¯g©g°kÓ.BÓCð%ôð: —]‘]ˆFà�K‰Kðð �
ôð —|‘|—~�Ø—7‘7˜5—>’>Ø—K‘KØlØ U¥¨S°­]¸CÀÕ<MÐNöð —W‘W˜[×)Ô)Ü<¸[ÈkÕJZÓ[�Hß#Ù ØŸ7™7Ð#6Ó7×]Ð]¼2¿7¹7×;KÑ;KÈCÐP[ÕL\Ó;]�DÜŸ'™'×*Ñ*¨4Ó0°Õ3×fÐf´r·w±w×7GÑ7GÈÈKÕHXÓ7YÐZ[Õ7\×fÐfÐ`f�CÜŸ:š: b›>×-Ñ-Ó/�DØ $˜v c U˜^�FÜ0°Ó@�CÜ!Ÿw™wŸ|™|¨KÓ=�HÜ—K’K¤§¡§¡°Ó 9ÀDÕIÜ—L’L Ô4Ø—K‘Kð JØ d°­M¸3¸|Õ;LÐM÷ñ% &ð. —‘Ð.Ó/ˆBßÜŸ'™'Ÿ,™, {°BÓ7�Ü—7‘7—>‘> '×*Ò*Ü8¸Ó@�GÜ Ÿg™gŸl™l¨;¸Ó@�GÜ—K’K¤§¡§¡°Ó 8À4ÕHÜ—L’L ¨'Ô2Ø—K‘KØQØ  &Ð)ôð —w‘wÐ9Ó:ˆHßÜŸG™GŸL™L¨°hÓ?�	Ü—7‘7—>‘> )×,Ò,Ü$AÀ&Ó$I�MÜ "§¡§¡¨[¸-Ó H�IÜ—K’K¤§¡§¡°	Ó :ÀTÕJÜ—L’L ¨IÔ6Ø—K‘KØVØ&¨Ð/ôð
 �K‰Kðð �	ô	ð —<‘<“>ˆDØ�K‰Kðð �	ôð 47·<±<´>ÓB±>¨aœh qžk±>ÑBˆD�‰N÷y ðz 	�‰ŒÜ”x “~Ó&¨Ð+ð
 	�
‰
�øôU ”zÐ"ô QÜ˜Ð!IÐJÓKÈSÐPÒPðQüòF C÷y �]ûô~ ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/ûð 	�
‰
�úsà   Á[ Á'#\ Â
:[1Ã
\ Ã$[1Ä
\ Ä([1Å[1Å
\ Å0[1Æ
\ Æ*A[1Ç:C[1Ë3[1ÌA[1Í4[1Î
C"[1Ñ-A[1Ò2B#[1ÕA[1ÖC[1Ù.[,Ú[1Ú-\ Û [)Û([)Û,[1Û1\	Û<\ Ü]Ü']Ü6]Ü7] Ý]Ý] Ý]&z/api/parts/<int:part_id>/imagesc           
      ó  € \         P                  P                  R 4      pV'       g   \        RR/4      R3# \	        4       p\        VP                  ;'       g    R4      ;'       g    Rp\        P                  P                  V4      ^,          ;'       g    Rp\        P                  ! ^4      P                  4       pV V 2p\        W4      p\        P                  P                  W'4      p\        P                  ! \        P                  P                  V4      RR7       VP!                  V4       \#        4       p	 V	P%                  4       ;_uu_ 4       p
V
P'                  RV 34       V
P)                  4       R	,          ^ 8X  d   ^M^ pV
P'                  R
WVRV34       V
P'                  RV
P*                  34       V
P)                  4       pRRR4       V	P-                  4        \        \/        X4      4      ^É3V	P1                  4        #   + '       g   i     LF; i  \2         dC   pT	P5                  4        \        R\7        T4      /4      R3u Rp?T	P1                  4        # Rp?ii ; i  T	P1                  4        i ; i)Úimagerâ   r—  r#  z	image.jpgz.jpgTrq   ú8SELECT COUNT(*) AS c FROM part_images WHERE part_id = %srÆ   rÏ  Úuploadedú'SELECT * FROM part_images WHERE id = %sNrã   )r   r�  r6   r   rˆ   r
   r±  ri   r+   rš   rÓ  rÔ  r²  r…   ru   rv   rÁ  r«   r¸   rN   r¹   rè   rÍ   rÔ   ræ   rn   ré   rê   )r©  rë  r�   Ú	safe_namerÝ  rÞ  r±  r�   Úfullr½   rU   rÌ  rÈ   rì   s   &             rF   Úpart_upload_imagerñ  +  sÞ  € ä�M‰M×Ñ˜gÓ&€EßÜ˜Ð!3Ð4Ó5°sÐ:Ð:Ü'Ó)€KÜ §¡× =Ð =°+Ó>×MÐMÀ+€IÜ
�'‰'×
Ñ
˜9Ó
% aÕ
(×
2Ð
2¨F€CÜ�:Š:�b‹>×ÑÓ€DØ�˜�uˆ~€HÜ
  Ó
3€CÜ�7‰7�<‰<˜Ó)€DÜ‡K‚K”—‘—‘ Ó%°Õ5Ø	‡J�JˆtÔä‹9€DðØ�[‰[�]Œ]˜cØ�K‰KÐRÐU\ÐT^Ô_Ø!Ÿl™l›n¨SÕ1°QÔ6™¸AˆJØ�K‰Kð BØ˜y¨*°jÐAôð �K‰KÐAÀCÇMÁMÐCSÔTØ—,‘,“.ˆC÷ ð 	�‰ŒÜ”x “}Ó% sÐ*ð
 	�
‰
�÷ �]ûô ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/ûð 	�
‰
�úsI   Ä?H ÅA7HÇ-H ÈH	ÈH ÈI,È*'I'ÉI,ÉI/ É'I,É,I/ É/Jz#/api/parts/<int:part_id>/images/urlc           	      ó2  € \         P                  ! R R7      ;'       g    / pVP                  R4      pV'       g   \        RR/4      R3# \	        4       p VP                  4       ;_uu_ 4       pVP                  RV 34       VP                  4       R,          ^ 8X  d   ^M^ pVP                  RWR	V34       VP                  R
VP                  34       VP                  4       pRRR4       VP                  4        \        \        X4      4      ^É3VP                  4        #   + '       g   i     LF; i  \         dC   pTP                  4        \        R\        T4      /4      R3u Rp?TP                  4        # Rp?ii ; i  TP                  4        i ; i)TrÜ   rÉ  râ   zurl requiredr#  rì  rÆ   rÊ  Úinternetrî  Nrã   )r   rç   r6   r   r«   r¸   rN   r¹   rè   rÍ   rÔ   ræ   rn   ré   rê   )r©  r@   Ú	image_urlr½   rU   rÌ  rÈ   rì   s   &       rF   Úpart_add_image_urlrõ  N  s=  € ä×Ò dÔ+×1Ð1¨r€GØ—‘˜EÓ"€IßÜ˜ Ð0Ó1°3Ð6Ð6Ü‹9€DðØ�[‰[�]Œ]˜cØ�K‰KÐRÐU\ÐT^Ô_Ø!Ÿl™l›n¨SÕ1°QÔ6™¸AˆJØ�K‰KØdØ Z°Ð<ôð �K‰KÐAÀCÇMÁMÐCSÔTØ—,‘,“.ˆC÷ ð 	�‰ŒÜ”x “}Ó% sÐ*ð
 	�
‰
�÷ �]ûô ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/ûð 	�
‰
�úsI   ÁD4 Á-A6D!Ã#-D4 Ä!D1	Ä,D4 Ä4FÄ?'E<Å&FÅ'F Å<FÆF ÆFz6/api/parts/<int:part_id>/images/<int:image_id>/primaryc                 ól  € \        4       p VP                  4       ;_uu_ 4       pVP                  R V 34       VP                  RW34       VP                  RV 34       VP                  4        Uu. uF  p\	        V4      NK  	  ppRRR4       VP                  4        \        X4      VP                  4        # u upi   + '       g   i     L@; i  \         dC   pTP                  4        \        R\        T4      /4      R3u Rp?TP                  4        # Rp?ii ; i  TP                  4        i ; i)z8UPDATE part_images SET is_primary = 0 WHERE part_id = %szDUPDATE part_images SET is_primary = 1 WHERE id = %s AND part_id = %szISELECT * FROM part_images WHERE part_id = %s ORDER BY is_primary DESC, idNrâ   rã   )r«   r¸   rN   rO   rÔ   rÍ   r   ræ   rn   ré   rê   )r©  Úimage_idr½   rU   rX   rÄ   rì   s   &&     rF   Úpart_set_primaryrø  h  sé   € ä‹9€DðØ�[‰[�]Œ]˜cØ�K‰KÐRÐU\ÐT^Ô_Ø�K‰KÐ^ÐaiÐ`sÔtØ�K‰KÐcÐfmÐeoÔpØ),¯©¬Ó8© A”H˜Q–K©ˆDÐ8÷	 ð
 	�‰ŒÜ�t‹}ð
 	�
‰
�ùò 9÷	 �]ûô ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/ûð 	�
‰
�úsY   ŒC ¤AB>Á0B9ÂB>Â"C Â9B>Â>C	Ã	C ÃDÃ'DÄDÄD! ÄDÄD! Ä!D3z./api/parts/<int:part_id>/images/<int:image_id>c                 ól  € \        4       p R pVP                  4       ;_uu_ 4       pVP                  RW34       VP                  4       pV'       g*   \	        RR/4      R3uuR R R 4       VP                  4        # VP                  R4      pVP                  RV34       R R R 4       VP                  4        V'       dd   \        P                  P                  \        4       V4      p\        P                  P                  V4      '       d   \        P                  ! V4       \        ^ÌR7      VP                  4        #   + '       g   i     L§; i  \         dC   pTP!                  4        \	        R\#        T4      /4      R3u R p?TP                  4        # R p?ii ; i  TP                  4        i ; i)	Nz@SELECT file_path FROM part_images WHERE id = %s AND part_id = %srâ   rò   ró   rÍ  z%DELETE FROM part_images WHERE id = %srô   rã   )r«   r¸   rN   r¹   r   ræ   r6   rÍ   ri   r+   r…   rˆ   rj   Úremover   rn   ré   rê   )r©  r÷  r½   rÍ  rU   rÈ   rð  rì   s   &&      rF   Úpart_delete_imagerû  z  s2  € ä‹9€DðØˆ	Ø�[‰[�]Œ]˜cØ�K‰KÐZÐ]eÐ\oÔpØ—,‘,“.ˆCßÜ ¨Ð5Ó6¸Ð;÷	 ‰]ð" 	�
‰
�ð Ÿ™ Ó,ˆIØ�K‰KÐ?À(ÀÔM÷ ð 	�‰ŒßÜ—7‘7—<‘<Ô 5Ó 7¸ÓCˆDÜ�w‰w�~‰~˜d×#Ò#Ü—	’	˜$”Ü˜sÔ#ð
 	�
‰
�÷# �]ûô ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/ûð 	�
‰
�úsY   ŒE ¦:D>Á 
E Á;$D>ÂE Â?A.E Ä>E	Å	E ÅFÅ'FÆFÆF! ÆFÆF! Æ!F3z"/api/parts/<int:part_id>/datasheetc                 ó  € \        4       p VP                  4       ;_uu_ 4       p\        P                  R 8X  Ed    \        P                  P                  R4      pV'       g*   \        RR/4      R3uuRRR4       VP                  4        # \        V 4      p\        P                  P                  \        4       V4      p\        V 4      p\        P                  P                  \        4       V4      p\        P                  ! \        P                  P                  V4      RR7       VP!                  V4       VP#                  RV 34       VP%                  4       pV'       g*   \        RR	/4      R
3uuRRR4       VP                  4        # VP                  R4      p	V	'       dj   W”8w  dd   \        P                  P                  \        4       V	4      p
\        P                  P'                  V
4      '       d   \        P(                  ! V
4       \+        WW4      pV'       g<   \        P                  P'                  V4      '       d   \        P(                  ! V4       TP#                  RYK'       d   TMRV 34       VP#                  RV 34       VP%                  4       pVP-                  4        \        \/        V4      4      uuRRR4       VP                  4        # VP#                  RV 34       VP%                  4       pV'       g*   \        RR/4      R
3uuRRR4       VP                  4        # \        P                  R8X  dú   VP                  R4      pV'       ds   \        P                  P                  \        4       V4      p\        P                  P'                  V4      '       d&   \1        V4      uuRRR4       VP                  4        # VP                  R4      '       d/   \3        VR,          RR7      uuRRR4       VP                  4        # \        RR/4      R
3uuRRR4       VP                  4        # VP                  R4      pV'       dd   \        P                  P                  \        4       V4      p\        P                  P'                  V4      '       d   \        P(                  ! V4       VP                  R4      pV'       dd   \        P                  P                  \        4       V4      p\        P                  P'                  V4      '       d   \        P(                  ! V4       VP#                  RV 34       VP-                  4        \5        ^ÌR7      uuRRR4       VP                  4        #   + '       g   i     MS; i  \6         dC   pTP9                  4        \        R\;        T4      /4      R3u Rp?TP                  4        # Rp?ii ; i TP                  4        R#   TP                  4        i ; i)rÚ   Ú	datasheetrâ   r—  r#  NTrq   z3SELECT datasheet_file_path FROM parts WHERE id = %szPart not foundró   rÐ  zVUPDATE parts SET datasheet_file_path = %s, datasheet_thumbnail_path = %s WHERE id = %srz  z\SELECT datasheet_file_path, datasheet_thumbnail_path, datasheet_url FROM parts WHERE id = %srò   rÕ   rx  i.  )ÚcodezNo datasheetrÑ  zZUPDATE parts SET datasheet_file_path = NULL, datasheet_thumbnail_path = NULL WHERE id = %srô   rã   )r«   r¸   r   rå   r�  r6   r   ræ   r¶  ri   r+   r…   rˆ   r¸  ru   rv   rÁ  rN   r¹   rj   rú  rÇ  rÍ   rÔ   r   r   r   rn   ré   rê   )r©  r½   rU   Úpdfr�   rð  Ú	thumb_relÚ
thumb_fullrY   ÚoldÚold_fullÚ	has_thumbrÈ   rÐ  rÑ  Úthumbrì   s   &                rF   Úpart_datasheetr  “  sD  € ä‹9€DðCØ�[‰[�]Œ]˜cÜ�~‰~ Õ'Ü—m‘m×'Ñ'¨Ó4�ßÜ" GÐ-?Ð#@ÓAÀ3ÐF÷	 ‰]ðD 	�
‰
�ô{ 1°Ó9�Ü—w‘w—|‘|Ô$9Ó$;¸SÓA�Ü9¸'ÓB�	ÜŸW™WŸ\™\Ô*?Ó*AÀ9ÓM�
Ü—’œBŸG™GŸO™O¨DÓ1¸DÕAØ—‘˜”Ø—‘ÐQÐT[ÐS]Ô^ØŸ<™<›>�ßÜ" GÐ-=Ð#>Ó?ÀÐD÷ ‰]ðD 	�
‰
�ðg —l‘lÐ#8Ó9�ß˜3œ:Ü!Ÿw™wŸ|™|Ô,AÓ,CÀSÓI�HÜ—w‘w—~‘~ h×/Ò/ÜŸ	š	 (Ô+Ü9¸$ÓK�	ß ¤R§W¡W§^¡^°J×%?Ò%?Ü—I’I˜jÔ)Ø—‘ØlØ¦y™)°d¸GÐDôð —‘Ð?À'ÀÔLØ—l‘l“n�Ø—‘”Üœx¨›}Ó-÷= ‰]ðD 	�
‰
�ðE �K‰KÐvð  zAð  yCô  DØ—,‘,“.ˆCßÜ ¨Ð5Ó6¸Ð;÷G ‰]ðD 	�
‰
�ô= �~‰~ Ô&Ø&)§g¡gÐ.CÓ&DÐ#ß&ÜŸ7™7Ÿ<™<Ô(=Ó(?ÐATÓU�DÜ—w‘w—~‘~ d×+Ò+Ü(¨›÷S ‰]ðD 	�
‰
�ð1 —7‘7˜?×+Ò+Ü# C¨Õ$8¸sÔC÷W ‰]ðD 	�
‰
�ô-  ¨Ð8Ó9¸3Ð>÷Y ‰]ðD 	�
‰
�ð) #&§'¡'Ð*?Ó"@Ðß"Ü—w‘w—|‘|Ô$9Ó$;Ð=PÓQ�Ü—7‘7—>‘> $×'Ò'Ü—I’I˜d”OØ'*§w¡wÐ/IÓ'JÐ$ß'ÜŸ™Ÿ™Ô%:Ó%<Ð>VÓW�Ü—7‘7—>‘> %×(Ò(Ü—I’I˜eÔ$Ø�K‰KØlØ�
ôð �K‰KŒMÜ 3Ô'÷{ ‰]ðD 	�
‰
�÷E �]ûô| ô /Ø�‰ŒÜ˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð	/úð} ðD 	�
‰
Žøˆ�
‰
�úsÜ   ŒV ¤=U=Á"U=Á0
V ÂC%U=Å0
V ÆU=Æ$B U=ÉA:U=Ê?
V Ë*U=ÌU=Ì
V Ì.-U=ÍAU=Î3
V ÏU=Ï%U=Ï8
V ÐU=Ð!
V Ð<U=ÑA;U=ÓBU=Õ"
V Õ=V	ÖV ÖW3 ÖV ÖWÖ'W×W×W3 ×W×W3 ×3Xz/api/images/searchc                  ó¶  € \         P                  P                  R 4      p V '       g   \        RR/4      R3# \        '       d   \
        '       g   \        R. RR/4      #  \        P                  P                  R\        R\
        R V R	R
R^
/4      p\        P                   P                  RV 2^
R7      ;_uu_ 4       p\        P                  ! VP                  4       P                  R4      4      pRRR4       . pXP                  R. 4       Fy  pTP                  RVP                  R4      RVP                  R
4      ;'       g    / P                  R4      ;'       g    VP                  R4      RVP                  R4      /4       K{  	  \        RV/4      #   + '       g   i     L®; i  \         d%   p\        R\!        T4      R. /4      R3u Rp?# Rp?ii ; i)r@  râ   z
q requiredr#  rÐ   Úmessagez\Image search not configured. Set PARTSINV_IMAGE_SEARCH_API_KEY and PARTSINV_IMAGE_SEARCH_CX.rÒ   ÚcxÚ
searchTyperë  Únumz+https://www.googleapis.com/customsearch/v1?r'   r)   NÚlinkÚ	thumbnailÚthumbnailLinkÚtitlerã   )r   rC  r6   r   r   r   r.   ÚparseÚ	urlencoder1   r2   r3   r4   r5   r:   rn   rê   )r@  r€  r?   r@   rÐ   rB   rì   s          rF   Úimage_searchr  Ü  sª  € ä�‰×Ñ˜Ó€AßÜ˜ Ð.Ó/°Ð4Ð4ß(Ó(×0HÓ0HÜ˜  Yð  1Oð  Pó  Qð  	Qð<Ü—‘×'Ñ'àÔ4ØÔ.Ø�QØ˜gØ�rðó
ˆô �^‰^×#Ñ#Ð&QÐRXÐQYÐ$ZÐdfÐ#×gÔgÐksÜ—j’j §¡£×!7Ñ!7¸Ó!@ÓAˆG÷ hàˆØ—K‘K ¨Ö,ˆDØ�L‰Là˜DŸH™H VÓ,Ø $§(¡(¨7Ó"3×"9Ð"9°r×!>Ñ!>¸Ó!O×!cÐ!cÐSW×S[ÑS[Ð\bÓScØ˜TŸX™X gÓ.ðöñ -ô ˜ Ð'Ó(Ð(÷ h×gûô ô <Ü˜¤ Q£¨°"Ð5Ó6¸Ð;Õ;ûð<úsD   ÁAF) Â<4FÃ0AF) ÅF) Å8F) ÆF&	Æ!F) Æ)GÆ4GÇGÇGz/api/settings/upload-dirc                  ót  € \        4       p \        P                  R 8X  d"   \        RV P	                  R\
        4      /4      # \        P                  ! RR7      ;'       g    / p\        VP	                  R4      ;'       g    R4      P                  4       ;'       g    RpW R&   \        V 4       \        RV/4      # )rÕ   r   TrÜ   r€   )
r`   r   rå   r   r6   r   rç   rê   r�   rx   )r   r@   r†   s      rF   Úsettings_upload_dirr  ý  s˜   € äÓ€DÜ‡~�~˜ÔÜ˜ T§X¡X¨kÔ;NÓ%OÐPÓQÐQÜ×Ò dÔ+×1Ð1¨r€GÜ�W—[‘[ Ó-×IÐIÐ1IÓJ×PÑPÓR×nÐnÐVn€JØ"ˆÑÜ�4ÔÜ�K Ð,Ó-Ð-re   z/api/settings/databasec                  ó  € \         P                  R 8X  d   \        \        4       4      # \         P                  ! RR7      ;'       g    / p \        4       p\        4       pV P                  RVR,          4      VR&   V P                  RVR,          4      VR&   V P                  RVR,          4      VR&   V P                  RVR,          4      VR&   RV 9   d   V P                  RR4      VR&   \        V4       \        \        4       4      # )	rÕ   TrÜ   r   r   r   r   r   r,   )	r   rå   r   r®   rç   r`   r}   r6   rx   )r@   r   Úcurrents      rF   Úsettings_databaser  	  sÛ   € ä‡~�~˜ÔÜÔ)Ó+Ó,Ð,Ü×Ò dÔ+×1Ð1¨r€GÜÓ€DÜ"Ó$€GØ—;‘;˜v w¨v¥Ó7€Dˆ�LØ—;‘;˜v w¨v¥Ó7€Dˆ�LØ—;‘;˜v w¨v¥Ó7€Dˆ�LØ—{‘{ :¨w°zÕ/BÓC€DˆÑØ�WÔØ"Ÿ;™; z°2Ó6ˆˆZÑÜ�4ÔÜÔ%Ó'Ó(Ð(re   z/api/settings/database/testc                  óX  € \         P                  ! R R7      ;'       g    / p RV P                  R4      ;'       g    RR\        V P                  R4      ;'       g    R4      RV P                  R4      RV P                  RR4      R	V P                  R	4      R
\        P
                  P                  /pRp \        P                  ! R/ VB pVP                  4       ;_uu_ 4       pVP                  R4       VP                  4        RRR4       \        RR /4      V'       d   VP                  4        # #   + '       g   i     L6; i  \         d<   p\        RRR\        T4      /4      u Rp?T'       d   TP                  4        # # Rp?ii ; i  T'       d   TP                  4        i i ; i)TrÜ   r   Ú	localhostr   iê  r   r   r,   r   r   NzSELECT 1ÚsuccessFr  r©   )r   rç   r6   rP   rz   r{   r|   rª   r¸   rN   r¹   r   ræ   rn   rê   )r@   Úconfigr½   rU   rì   s        rF   Úsettings_database_testr    sI  € ä×Ò dÔ+×1Ð1¨r€Gà�—‘˜FÓ#×2Ð2 {Ø”�G—K‘K Ó'×/Ð/¨4Ó0Ø�—‘˜FÓ#Ø�G—K‘K 
¨BÓ/Ø�G—K‘K 
Ó+Ø”w—‘×1Ñ1ð€Fð €Dð
Ü�ŠÑ( Ñ(ˆØ�[‰[�]Œ]˜cØ�K‰K˜
Ô#Ø�L‰LŒN÷ ô ˜	 4Ð(Ó)÷ Ø�J‰J�Lð ÷ �]ûô ô >Ü˜	 5¨)´S¸³VÐ<Ó=Ô=çØ�J‰J�Lð ûð>û÷ Ø�J‰J�Lð úsH   Â4.E Ã""D2ÄE Ä2E	Ä=E ÅFÅFÅ'FÅ(F ÆFÆF ÆF)z/api/settings/uic                  ó,  € \        4       p \        P                  R 8X  d   \        \	        4       4      # \        P
                  ! RR7      ;'       g    / pRV9   d   \        VP                  R4      4      V R&   \        V 4       \        \	        4       4      # )rÕ   TrÜ   r_   )	r`   r   rå   r   rd   rç   ra   r6   rx   )r   r@   s     rF   Úsettings_uir  3  st   € äÓ€DÜ‡~�~˜ÔÜÔ-Ó/Ó0Ð0Ü×Ò dÔ+×1Ð1¨r€GØ�wÔÜ! '§+¡+¨lÓ";Ó<ˆˆ\ÑÜ�4ÔÜÔ)Ó+Ó,Ð,re   z#/api/settings/footprints/sync-kicadc            	      óØ  € \        4       p  \        V 4       V P                  4       ;_uu_ 4       p\        V4      pR R R 4       V P	                  4        \        RR/XC4      V P                  4        #   + '       g   i     L?; i  \         dE   pT P                  4        \        RRR\        T4      /4      R3u R p?T P                  4        # R p?ii ; i  T P                  4        i ; i)Nr  TFrâ   rã   )
r«   rÎ   r¸   r]   rÍ   r   ræ   rn   ré   rê   )r½   rU   Úresultrì   s       rF   Úsettings_footprints_sync_kicadr!  ?  s®   € ä‹9€Dð
Ü�tÔØ�[‰[�]Œ]˜cÜ+¨CÓ0ˆF÷ à�‰ŒÜ˜	 4Ð2¨6Ð2Ó3ð
 	�
‰
�÷ �]ûô ô AØ�‰ŒÜ˜	 5¨'´3°q³6Ð:Ó;¸SÐ@Ô@à�
‰
�ûð	Aûð 	�
‰
�úsE   Œ#B ¯A2»&B Á2B	Á=B ÂCÂ)CÂ9CÂ:C ÃCÃC ÃC)z/api/settings/backup/fullc                  ó†  € \        4       p  \        V 4       \        V 4      pR \        P                  ! 4       P                  R4       R2p\        VRRRV R2/R7      V P                  4        #   \         d3   p\        R\        T4      /4      R	3u R
p?T P                  4        # R
p?ii ; i  T P                  4        i ; i)Úparts_inventory_backup_z%Y%m%d_%H%M%Sz.sqlzapplication/sqlr�  zattachment; filename="Ú"r�  râ   rã   N)r«   rÎ   rÊ   r   r¶   Ústrftimer   ræ   rn   r   rê   )r½   Údump_sqlr±  rì   s       rF   Úsettings_backup_fullr'  O  s¬   € ä‹9€DðÜ�tÔÜ+¨DÓ1ˆØ,¬X¯\ª\«^×-DÑ-DÀ_Ó-UÐ,VÐVZÐ[ˆÜØØ&Ø*Ð.DÀXÀJÈaÐ,PÐQô
ð 	�
‰
�øô ô /Ü˜¤ Q£Ð(Ó)¨3Ð.Ô.à�
‰
�ûð/ûð 	�
‰
�ús0   ŒAA. Á.B+Á9B&ÂB+ÂB. Â&B+Â+B. Â.C z/uploads/<path:filename>c                 óÀ  € \        4       pT ;'       g    R P                  RR4      p\        P                  P	                  W4      p\        P                  P                  V4      '       d   \        W4      # \        P                  P                  V4      w  rE\        P                  P                  V4      w  rg\        P                  P	                  W4      pV'       Edm   \        P                  P                  V4      '       EdG   V'       d‡   V'       d0   \        P                  P	                  WF4      P                  RR4      MTp	\        P                  P                  \        P                  P	                  W4      4      '       d   \        W4      # \        P                  P	                  W† R24      p
\        P                  ! V
4       Uu. uF,  p\        P                  P                  V4      '       g   K*  VNK.  	  ppV'       dC   \        P                  P                  V^ ,          V4      P                  RR4      p\        W4      # \        RR/4      R3# u upi )r,   rŠ   r‹   r–   râ   rò   ró   )rˆ   r�   ri   r+   r…   r™   r	   r8   rš   r›   rœ   Úrelpathr   )r±  r�   Ú
normalizedr    r¡   r¢   r£   rÝ  r¥   Ú
no_ext_relr  r  ÚmatchesÚ	rel_matchs   &             rF   Úuploadsr.  a  s�  € ä'Ó)€KØ—.�.˜b×)Ñ)¨$°Ó4€JÜ—‘—‘˜[Ó5€IÜ	‡w�w‡~�~�i× Ò Ü" ;Ó;Ð;äŸ™Ÿ™ jÓ1Ñ€GÜ—‘× Ñ  Ó*�I€DÜ�g‰g�l‰l˜;Ó0€G÷ €t”—‘—‘˜g×&Ó&ßßKRœŸ™Ÿ™ gÓ4×<Ñ<¸TÀ3ÔGÐX\ˆJÜ�w‰w�~‰~œbŸg™gŸl™l¨;ÓC×DÒDÜ*¨;ÓCÐCÜ—'‘'—,‘,˜w¨&°¨Ó4ˆÜ"Ÿiši¨Ô0ÓFÑ0˜´B·G±G·N±NÀ1×4E—1�1Ñ0ˆÐFßÜŸ™Ÿ™¨°­
°KÓ@×HÑHÈÈsÓSˆIÜ& {Ó>Ð>ä�G˜[Ð)Ó*¨CÐ/Ð/ùò Gs   Ç'IÇ:Ir‹   r+   r,   )Údefaultsz/<path:path>c                 óú  € \         pV P                  R 4      '       g   V P                  R4      '       d   \        RR/4      R3# V '       dN   \        P                  P                  \        P                  P                  W4      4      '       d   \        W4      # \        P                  P                  VR4      p\        P                  P                  V4      '       d   \        VR4      # \        RRRRR	V/4      R
3# )zapi/r•   râ   rò   ró   z
index.htmlz!PartsInventory frontend not builtr  z@Build the React client and place output in PARTSINV_CLIENT_DIST.Údisti÷  )r   r˜   r   ri   r+   rj   r…   r	   )r+   Údist_dirÚ
index_paths   &  rF   Úspar4  |  sÉ   € ô $€HØ‡��v×Ò $§/¡/°*×"=Ò"=Ü˜ Ð-Ó.°Ð3Ð3ß”—‘—‘œrŸw™wŸ|™|¨HÓ;×<Ò<Ü" 8Ó2Ð2Ü—‘—‘˜h¨Ó5€JÜ	‡w�w‡~�~�j×!Ò!Ü" 8¨\Ó:Ð:ÜàÐ8ØÐYØ�Hð	
óð ðð re   )rÕ   rï   rð   )rÕ   rÚ   rð   )eÚ__doc__rŠ  rœ   r³   r2   ri   r  rÕ  Úurllib.parser.   Úurllib.requestr   rz   Úflaskr   r   r   r   r   r   r	   Úwerkzeug.utilsr
   r¼  rn   r  r   r   r   r   r   r   r   r   r   Ú__name__Úbpr{   r|   Ú	DB_CONFIGr+   r…   rv   rƒ   rk   Ú_UPLOAD_OVERRIDE_FILEr0   rR   rG   r]   rd   r`   rx   r}   rˆ   r§   r«   r®   rÊ   rÎ   rÔ   ÚrouterÙ   rí   rú   rÿ   r  r  r  r   r5  r7  r>  rE  rI  rU  rZ  r…  r‡  r”  r¦  r®  r²  r¶  r¸  rÇ  ré  rñ  rõ  rø  rû  r  r  r  r  r  r  r!  r'  r.  r4  r©   re   rF   Ú<module>r?     s/  ðñó Û Û 	Û Û 	Û 	Û Û Û Ý ã ß a× aÑ aÝ *ðÛ÷
÷ 
õ 
ñ Ð Ó*€ð ÐØ
ÐØ
ÐØÐ$ØÐ Ø�7—?‘?×-Ñ-Ø�%ð€	ð —G‘G—L‘L §¡§¡°·±·±ÀÓ1JÓ!KÐM]Ð_eÐgwÓxÐ Ø)Ð ØhÐ ð3Ø
ð3à
ð3ð ð3ð ð	3ð
 ð3ð ð3ð ð3ð ð3ð ð3ð ð3ð ð3ð ð3ð ð3ð ð3ð ð3ð  ð!3ð" ð#3ð$ ð%3ð& ð'3ð( ð)3ð* ð+3ð, ð-3ð. ð/3ð0 ð13ð2 ð33ð4 ð53ð6 ð73ð8 ð93ð: ð;3ð< ð=3ð> ð?3ð@ ðA3ðB ðC3ðD ðE3ðF ðG3ðH ðI3ðJ ðK3ðL ðM3ðN ðO3ðP ðQ3ðR ðS3ðT ðU3ðV ðW3ðX ðY3ðZ ð[3ð\ ð]3ð^ ð_3ð` ða3ðb ðc3ðd ðe3Ð òl&ò(!SòHòò%ò
ò;ò(òV5òò)òXCòLð ‡�ˆ- % €Ó)ñ&ó *ð&ð ‡�Ð
 e¨V _€Ó5ñó 6ðð0 ‡�Ð
)°E¸8Ð3D€ÓEñó Fðò>&ð ‡�Ð
"¨U°F¨O€Ó<ñó =ðð6 ˆ(�C˜ q¨&°!°V¸QÐ	?Øˆ8�T˜<¨¨F°A°v¸qÐ
AØˆ8�T˜<¨¨F°A°v¸qÐ
AðÐ ò
òð ‡�Ð
-¸°x€Ó@ñHó AðHðV ‡�Ð
0¸5À(Ð:K€ÓLñó Mðð> ‡�Ð
>ÈÈ	€ÓRñ ó Sð ðF ‡�Ð
 e W€Ó-ñ*ó .ð*òZòð@ ‡�Ð
"¨U¨G€Ó4ñó 5ðð( ‡�ˆ, ¨ €Ó0ñyó 1ðyðx ‡�Ð
0¸5¸'€ÓBñó Cðð ‡�Ð
¨ w€Ó/ñ]ó 0ð]ð@ ‡�Ð
¨ x€Ó0ñHó 1ðHðV ‡�Ð
$Ò.F€ÓGñtó Hðtòn<ò:ò@òð* ‡�Ð
.¸¸€ÓAñRó BðRðj ‡�Ð
+°f°X€Ó>ñó ?ððD ‡�Ð
/¸&¸€ÓBñó Cðð2 ‡�Ð
BÈWÈI€ÓVñó Wðð" ‡�Ð
:ÀXÀJ€ÓOñó Pðð0 ‡�Ð
.Ò8Q€ÓRñEó SðEðP ‡�Ð
¨¨€Ó0ñ<ó 1ð<ð@ ‡�Ð
$¨u°e¨n€Ó=ñ.ó >ð.ð ‡�Ð
"¨U°E¨N€Ó;ñ)ó <ð)ð  ‡�Ð
'°&°€Ó:ñó ;ðð0 ‡�Ð
 u¨e n€Ó5ñ-ó 6ð-ð ‡�Ð
/¸&¸€ÓBñó Cðð ‡�Ð
%°¨w€Ó7ñó 8ðð" ‡�Ð
$¨u¨g€Ó6ñ0ó 7ð0ð4 ‡�ˆ#˜ ˜€Ó%Ø‡�ˆ.Óñó ó &òøðS; ô ØƒDðús   Á
S  Ó 	SÓS