diff options
| author | trisusilo48 <tri.susilo@altama.co.id> | 2025-01-13 11:24:08 +0700 |
|---|---|---|
| committer | trisusilo48 <tri.susilo@altama.co.id> | 2025-01-13 11:24:08 +0700 |
| commit | fcefddc96acc561ec13d52e734eaf04b041d4a0b (patch) | |
| tree | 5214a97eb25c3790cdd5b498278d924aac1f0336 | |
| parent | bef3ba4c18d585bc0980942d91b5fcb4d44427e1 (diff) | |
update export xml by selected invoice
| -rw-r--r-- | indoteknik_custom/models/account_move.py | 32 | ||||
| -rw-r--r-- | indoteknik_custom/models/coretax_fatur.py | 69 | ||||
| -rw-r--r-- | indoteknik_custom/views/account_move.xml | 8 |
3 files changed, 85 insertions, 24 deletions
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 725b3c2d..42678847 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -325,3 +325,35 @@ class AccountMove(models.Model): # if rec.statement_line_id and not rec.statement_line_id.statement_id.is_edit and rec.statement_line_id.statement_id.state == 'confirm': # raise UserError('Bank Statement di Lock, Minta admin reconcile untuk unlock') # return res + + def validate_faktur_for_export(self): + invoices = self.filtered(lambda inv: not inv.is_efaktur_exported and + inv.state == 'posted' and + inv.move_type == 'out_invoice') + + invalid_invoices = self - invoices + if invalid_invoices: + invalid_ids = ", ".join(str(inv.id) for inv in invalid_invoices) + raise UserError(_( + "Faktur dengan ID berikut tidak valid untuk diekspor: {}.\n" + "Pastikan faktur dalam status 'posted', belum diekspor, dan merupakan 'out_invoice'.".format(invalid_ids) + )) + + return invoices + + def export_faktur_to_xml(self): + + valid_invoices = self.validate_faktur_for_export() + + # Panggil model coretax.faktur untuk menghasilkan XML + coretax_faktur = self.env['coretax.faktur'].create({}) + response = coretax_faktur.export_to_download(invoices=valid_invoices) + + current_time = datetime.utcnow() + # Tandai faktur sebagai sudah diekspor + valid_invoices.write({ + 'is_efaktur_exported': True, + 'date_efaktur_exported': current_time, # Set tanggal ekspor + }) + + return response diff --git a/indoteknik_custom/models/coretax_fatur.py b/indoteknik_custom/models/coretax_fatur.py index 32082774..00a8f5ab 100644 --- a/indoteknik_custom/models/coretax_fatur.py +++ b/indoteknik_custom/models/coretax_fatur.py @@ -2,6 +2,7 @@ from odoo import models, fields import xml.etree.ElementTree as ET from xml.dom import minidom import base64 +import re class CoretaxFaktur(models.Model): _name = 'coretax.faktur' @@ -9,68 +10,88 @@ class CoretaxFaktur(models.Model): export_file = fields.Binary(string="Export File", ) export_filename = fields.Char(string="Export File", ) + + def validate_and_format_number(slef, input_number): + # Hapus semua karakter non-digit + cleaned_number = re.sub(r'\D', '', input_number) + + # Hitung jumlah digit + digit_count = len(cleaned_number) + + # Jika jumlah digit kurang dari 15, tambahkan nol di depan + if digit_count < 16: + cleaned_number = cleaned_number.zfill(16) + + return cleaned_number - def generate_xml(self): + def generate_xml(self, invoices=None): # Buat root XML root = ET.Element('TaxInvoiceBulk', { 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance", 'xsi:noNamespaceSchemaLocation': "TaxInvoice.xsd" }) - ET.SubElement(root, 'TIN').text = '74.226.022.7-086.000' + ET.SubElement(root, 'TIN').text = '0742260227086000' # Tambahkan elemen ListOfTaxInvoice list_of_tax_invoice = ET.SubElement(root, 'ListOfTaxInvoice') # Dapatkan data faktur - inv_obj = self.env['account.move'] - invoices = inv_obj.search([('is_efaktur_exported','=',True), - ('state','=','posted'), - ('efaktur_id','!=', False), - ('move_type','=','out_invoice')], limit = 5) + # inv_obj = self.env['account.move'] + # invoices = inv_obj.search([('is_efaktur_exported','=',True), + # ('state','=','posted'), + # ('efaktur_id','!=', False), + # ('move_type','=','out_invoice')], limit = 5) + for invoice in invoices: tax_invoice = ET.SubElement(list_of_tax_invoice, 'TaxInvoice') + buyerTIN = self.validate_and_format_number(invoice.partner_id.npwp) if invoice.partner_id.npwp else '0000000000000000' + buyerIDTKU = buyerTIN.ljust(len(buyerTIN) + 6, '0') if invoice.partner_id.npwp else '000000' # Tambahkan elemen faktur ET.SubElement(tax_invoice, 'TaxInvoiceDate').text = invoice.invoice_date.strftime('%Y-%m-%d') if invoice.invoice_date else '' ET.SubElement(tax_invoice, 'TaxInvoiceOpt').text = 'Normal' - ET.SubElement(tax_invoice, 'TrxCode').text = '01' + ET.SubElement(tax_invoice, 'TrxCode').text = '04' ET.SubElement(tax_invoice, 'AddInfo') ET.SubElement(tax_invoice, 'CustomDoc') ET.SubElement(tax_invoice, 'RefDesc').text = invoice.name ET.SubElement(tax_invoice, 'FacilityStamp') ET.SubElement(tax_invoice, 'SellerIDTKU').text = '0742260227086000000000' - ET.SubElement(tax_invoice, 'BuyerTin').text = invoice.partner_id.npwp or '' - ET.SubElement(tax_invoice, 'BuyerDocument').text = 'TIN' - ET.SubElement(tax_invoice, 'BuyerCountry').text = 'IND' + ET.SubElement(tax_invoice, 'BuyerTin').text = buyerTIN + ET.SubElement(tax_invoice, 'BuyerDocument').text = 'TIN' if invoice.partner_id.npwp else 'Other ID' + ET.SubElement(tax_invoice, 'BuyerCountry').text = 'IDN' + ET.SubElement(tax_invoice, 'BuyerDocumentNumber').text = '-' + ET.SubElement(tax_invoice, 'BuyerName').text = invoice.partner_id.nama_wajib_pajak or '' + ET.SubElement(tax_invoice, 'BuyerAdress').text = invoice.partner_id.alamat_lengkap_text or '' ET.SubElement(tax_invoice, 'BuyerEmail').text = invoice.partner_id.email or '' - ET.SubElement(tax_invoice, 'BuyerIDTKU').text = '' + ET.SubElement(tax_invoice, 'BuyerIDTKU').text = buyerIDTKU # Tambahkan elemen ListOfGoodService list_of_good_service = ET.SubElement(tax_invoice, 'ListOfGoodService') for line in invoice.invoice_line_ids: + otherTaxBase = round(line.price_subtotal * (11/12)) if line.price_subtotal else 0 good_service = ET.SubElement(list_of_good_service, 'GoodService') - ET.SubElement(good_service, 'Opt').text = 'B' if line.product_id.type == 'service' else 'A' - ET.SubElement(good_service, 'Code').text = line.product_id.default_code + ET.SubElement(good_service, 'Opt').text = 'A' + ET.SubElement(good_service, 'Code') ET.SubElement(good_service, 'Name').text = line.name ET.SubElement(good_service, 'Unit').text = 'UM.0018' - ET.SubElement(good_service, 'Price').text = str(line.price_unit) + ET.SubElement(good_service, 'Price').text = str(round(line.price_subtotal/line.quantity, 2)) if line.price_subtotal else '0' ET.SubElement(good_service, 'Qty').text = str(line.quantity) - ET.SubElement(good_service, 'TotalDiscount').text = str(line.discount) - ET.SubElement(good_service, 'TaxBase').text = str(line.price_subtotal) - ET.SubElement(good_service, 'OtherTaxBase').text = str(line.price_subtotal) - ET.SubElement(good_service, 'VATRate').text = '0,11' - ET.SubElement(good_service, 'VAT').text = str(line.price_total * 0.11) - ET.SubElement(good_service, 'STLGRate').text = '' - ET.SubElement(good_service, 'STLG').text = '' + ET.SubElement(good_service, 'TotalDiscount').text = '0' + ET.SubElement(good_service, 'TaxBase').text = str(round(line.price_subtotal)) if line.price_subtotal else '0' + ET.SubElement(good_service, 'OtherTaxBase').text = str(otherTaxBase) + ET.SubElement(good_service, 'VATRate').text = '12' + ET.SubElement(good_service, 'VAT').text = str(round(otherTaxBase * 0.12, 2)) + ET.SubElement(good_service, 'STLGRate').text = '0' + ET.SubElement(good_service, 'STLG').text = '0' # Pretty print XML xml_str = ET.tostring(root, encoding='utf-8') xml_pretty = minidom.parseString(xml_str).toprettyxml(indent=" ") return xml_pretty - def export_to_download(self): + def export_to_download(self, invoices): # Generate XML content - xml_content = self.generate_xml() + xml_content = self.generate_xml(invoices) # Encode content to Base64 xml_encoded = base64.b64encode(xml_content.encode('utf-8')) diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 2863af57..4cc35b6d 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -163,5 +163,13 @@ <field name="state">code</field> <field name="code">action = records.open_form_multi_create_reklas_penjualan()</field> </record> + + <record id="action_export_faktur" model="ir.actions.server"> + <field name="name">Export Faktur ke XML</field> + <field name="model_id" ref="account.model_account_move" /> + <field name="binding_model_id" ref="account.model_account_move" /> + <field name="state">code</field> + <field name="code">action = records.export_faktur_to_xml()</field> + </record> </data> </odoo>
\ No newline at end of file |
