uplatnica_generator.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import os
  2. from fpdf import FPDF
  3. import config
  4. from fpdf import FPDF
  5. import os
  6. import config
  7. def format_amount(amount):
  8. return f"{amount:.2f}".replace(".", ",")
  9. def generate_uplatnica(order_id, payer_name, payer_address, amount):
  10. pdf = FPDF(orientation='P', unit='mm', format='A4')
  11. pdf.set_auto_page_break(False)
  12. pdf.add_page()
  13. pdf.set_font("helvetica", size=7)
  14. # === UPLATNICA AREA (top of A4) ===
  15. pdf.rect(0, 0, 210, 99)
  16. # Vertical divider
  17. pdf.line(105, 0, 105, 99)
  18. # ===== TOP OPTIONS =====
  19. labels = ["Hitnost", "Prenos", "Uplata", "Isplata"]
  20. start_x = 110
  21. step = 22
  22. for i, label in enumerate(labels):
  23. x = start_x + i * step
  24. pdf.set_xy(x, 2)
  25. pdf.cell(14, 4, label)
  26. pdf.rect(x + 14, 2, 4, 4)
  27. if label == "Uplata":
  28. pdf.line(x + 14, 2, x + 18, 6)
  29. pdf.line(x + 18, 2, x + 14, 6)
  30. # ===== LEFT =====
  31. pdf.set_font("helvetica", "B", 8)
  32. pdf.set_xy(5, 5)
  33. pdf.cell(95, 5, "NALOG PLATIOCA", align="C")
  34. pdf.rect(5, 12, 95, 14)
  35. pdf.set_font("helvetica", size=9)
  36. pdf.set_xy(7, 14)
  37. pdf.cell(90, 4, payer_name[:40])
  38. pdf.set_xy(7, 18)
  39. pdf.cell(90, 4, payer_address[:40])
  40. pdf.set_font("helvetica", size=6)
  41. pdf.set_xy(5, 26)
  42. pdf.cell(95, 4, "(Naziv platioca)", align="C")
  43. pdf.rect(5, 30, 95, 14)
  44. pdf.set_font("helvetica", size=9)
  45. pdf.set_xy(7, 32)
  46. pdf.cell(90, 4, "Usluge 3D stampe")
  47. pdf.set_xy(7, 36)
  48. pdf.cell(90, 4, f"Narudzba {order_id}")
  49. pdf.set_font("helvetica", size=6)
  50. pdf.set_xy(5, 44)
  51. pdf.cell(95, 4, "(Svrha placanja)", align="C")
  52. pdf.rect(5, 48, 95, 14)
  53. pdf.set_font("helvetica", size=9)
  54. pdf.set_xy(7, 50)
  55. pdf.cell(90, 4, config.COMPANY_NAME[:40])
  56. pdf.set_font("helvetica", size=6)
  57. pdf.set_xy(5, 62)
  58. pdf.cell(95, 4, "(Naziv primaoca)", align="C")
  59. pdf.line(5, 90, 100, 90)
  60. pdf.set_xy(5, 90)
  61. pdf.cell(95, 4, "(Potpis platioca)", align="C")
  62. # ===== RIGHT =====
  63. pdf.rect(110, 12, 95, 8)
  64. pdf.set_font("helvetica", size=7)
  65. pdf.set_xy(110, 22)
  66. pdf.cell(10, 4, "EUR")
  67. pdf.rect(120, 22, 50, 10)
  68. pdf.rect(175, 22, 30, 10)
  69. pdf.set_font("helvetica", "B", 11)
  70. pdf.set_xy(120, 24)
  71. pdf.cell(50, 6, format_amount(amount), align="C")
  72. pdf.set_xy(175, 24)
  73. pdf.cell(30, 6, "121", align="C")
  74. pdf.set_font("helvetica", size=6)
  75. pdf.set_xy(120, 32)
  76. pdf.cell(50, 4, "(Iznos)", align="C")
  77. pdf.set_xy(175, 32)
  78. pdf.cell(30, 4, "(Sifra)", align="C")
  79. pdf.rect(110, 36, 95, 10)
  80. pdf.set_font("helvetica", size=10)
  81. pdf.set_xy(110, 38)
  82. pdf.cell(95, 6, config.ZIRO_RACUN, align="C")
  83. pdf.rect(110, 50, 20, 8)
  84. pdf.rect(135, 50, 70, 8)
  85. pdf.set_xy(110, 52)
  86. pdf.cell(20, 4, "00", align="C")
  87. pdf.set_xy(135, 52)
  88. pdf.cell(70, 4, str(order_id), align="C")
  89. pdf.line(110, 90, 205, 90)
  90. pdf.set_xy(110, 90)
  91. pdf.cell(95, 4, "(Potpis primaoca)", align="C")
  92. # ===== SAVE =====
  93. pdf_dir = os.path.join(config.UPLOAD_DIR, "invoices")
  94. os.makedirs(pdf_dir, exist_ok=True)
  95. filename = f"uplatnica_order_{order_id}.pdf"
  96. filepath = os.path.join(pdf_dir, filename)
  97. pdf.output(filepath)
  98. return os.path.join("uploads", "invoices", filename).replace("\\", "/")
  99. def generate_predracun(order_id, company_name, company_pib, company_address, amount, items=None):
  100. """Generates a formal Proforma Invoice (Predračun) for companies"""
  101. pdf = FPDF(orientation='P', unit='mm', format='A4')
  102. pdf.add_page()
  103. # Fonts
  104. pdf.set_font("helvetica", "B", 16)
  105. pdf.cell(0, 10, "PREDRACUN (Proforma Invoice)", ln=True, align='C')
  106. pdf.set_font("helvetica", "", 10)
  107. pdf.cell(0, 10, f"Broj narudzbe / Order ID: {order_id}", ln=True, align='C')
  108. pdf.ln(5)
  109. # Supplier info (Left)
  110. pdf.set_font("helvetica", "B", 10)
  111. pdf.cell(95, 5, "PRODAVAC / SUPPLIER:", ln=False)
  112. # Customer info (Right)
  113. pdf.cell(95, 5, "KUPAC / CUSTOMER:", ln=True)
  114. pdf.set_font("helvetica", "", 10)
  115. current_y = pdf.get_y()
  116. # Left column (Supplier)
  117. pdf.set_xy(10, current_y)
  118. pdf.multi_cell(90, 5, f"{config.COMPANY_NAME}\n{config.COMPANY_ADDRESS}\nPIB: {config.COMPANY_PIB}\nZiro racun: {config.ZIRO_RACUN}")
  119. # Right column (Customer)
  120. pdf.set_xy(105, current_y)
  121. pdf.multi_cell(90, 5, f"{company_name}\nAddress: {company_address}\nPIB: {company_pib}")
  122. pdf.ln(10)
  123. pdf.set_xy(10, pdf.get_y() + 5)
  124. # Table Header
  125. pdf.set_font("helvetica", "B", 10)
  126. pdf.set_fill_color(240, 240, 240)
  127. pdf.cell(10, 8, "#", border=1, fill=True)
  128. pdf.cell(100, 8, "Opis / Description", border=1, fill=True)
  129. pdf.cell(20, 8, "Kol / Qty", border=1, fill=True, align='C')
  130. pdf.cell(30, 8, "Cjena / Price", border=1, fill=True, align='R')
  131. pdf.cell(30, 8, "Iznos / Total", border=1, fill=True, align='R', ln=True)
  132. # Table Content
  133. pdf.set_font("helvetica", "", 9)
  134. pdv_rate = getattr(config, 'PDV_RATE', 21)
  135. total_base = 0.0
  136. total_pdv = 0.0
  137. if not items:
  138. # Fallback
  139. price_total = float(amount)
  140. price_base = price_total / (1 + pdv_rate/100)
  141. pdv_amount = price_total - price_base
  142. total_base = price_base
  143. total_pdv = pdv_amount
  144. pdf.cell(10, 8, "1", border=1)
  145. pdf.cell(100, 8, f"Usluge 3D stampe (Narudzba {order_id})", border=1)
  146. pdf.cell(20, 8, "1", border=1, align='C')
  147. pdf.cell(30, 8, format_amount(price_base), border=1, align='R')
  148. pdf.cell(30, 8, format_amount(price_total), border=1, align='R', ln=True)
  149. else:
  150. for i, item in enumerate(items):
  151. pdf.cell(10, 8, str(i + 1), border=1)
  152. pdf.cell(100, 8, str(item.get('name', '3D Print'))[:50], border=1)
  153. pdf.cell(20, 8, str(item.get('quantity', 1)), border=1, align='C')
  154. p_total = float(item.get('price', 0)) * item.get('quantity', 1)
  155. p_base = p_total / (1 + pdv_rate/100)
  156. p_pdv = p_total - p_base
  157. total_base += p_base
  158. total_pdv += p_pdv
  159. pdf.cell(30, 8, format_amount(p_base / item.get('quantity', 1)), border=1, align='R')
  160. pdf.cell(30, 8, format_amount(p_total), border=1, align='R', ln=True)
  161. # Breakdown
  162. pdf.ln(5)
  163. pdf.set_font("helvetica", "", 10)
  164. pdf.cell(160, 6, "Osnovica / Base Amount:", align='R')
  165. pdf.cell(30, 6, format_amount(total_base), align='R', ln=True)
  166. pdf.cell(160, 6, f"PDV {pdv_rate}% / VAT Amount:", align='R')
  167. pdf.cell(30, 6, format_amount(total_pdv), align='R', ln=True)
  168. # Total
  169. pdf.set_font("helvetica", "B", 12)
  170. pdf.cell(160, 10, "UKUPNO / TOTAL (EUR):", align='R')
  171. pdf.cell(30, 10, format_amount(float(amount)), align='R', ln=True)
  172. # Footer
  173. pdf.ln(20)
  174. pdf.set_font("helvetica", "I", 8)
  175. pdf.multi_cell(0, 5, "Predracun je validan bez pecata i potpisa. Placanje se vrsi u roku od 3 dana na navedeni ziro racun.\nThis is a proforma invoice and is valid without stamp and signature.")
  176. # Save
  177. pdf_dir = os.path.join(config.UPLOAD_DIR, "invoices")
  178. os.makedirs(pdf_dir, exist_ok=True)
  179. filename = f"predracun_order_{order_id}.pdf"
  180. filepath = os.path.join(pdf_dir, filename)
  181. pdf.output(filepath)
  182. return os.path.join("uploads", "invoices", filename).replace("\\", "/")