Initial commit

This commit is contained in:
Abdul Aziz Amrullah 2026-03-30 11:15:36 +07:00
commit 652688fe8b
6 changed files with 139 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
venv/
__pycache__/
*.pyc
.env

1
__init__.py Normal file
View File

@ -0,0 +1 @@
from . import models

18
__manifest__.py Normal file
View File

@ -0,0 +1,18 @@
{
'name': 'Purchase Export BC Format',
'version': '1.0',
'category': 'Purchases',
'summary': 'Export Purchase Orders to BC Excel format',
'author': 'Aziz',
'description': """
This module adds a button in the Purchase Order form view to export PO
into a specific BC Excel format.
""",
'depends': ['purchase'],
'data': [
'views/purchase_order_views.xml',
],
'installable': True,
'application': False,
'license': 'LGPL-3',
}

1
models/__init__.py Normal file
View File

@ -0,0 +1 @@
from . import purchase_order

102
models/purchase_order.py Normal file
View File

@ -0,0 +1,102 @@
import base64
import io
import logging
try:
import xlsxwriter
except ImportError:
xlsxwriter = None
from odoo import models, _
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
def action_export_bc(self):
self.ensure_one()
if not xlsxwriter:
raise UserError(_("The Python library 'xlsxwriter' is required. Please install it."))
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
header_format = workbook.add_format({
'bold': True, 'align': 'center', 'valign': 'vcenter', 'border': 1
})
headers = ["Type", "Item No.", "Description", "Qty", "Satuan"]
lines_by_category = {}
for line in self.order_line:
# Handle display_type like line_section or line_note which shouldn't be exported as items
if line.display_type in ('line_section', 'line_note'):
continue
categ_name = line.product_id.categ_id.name or 'Uncategorized'
# Sheet names in Excel cannot exceed 31 characters
categ_name = str(categ_name)[:31]
# Excel sheet names cannot contain certain characters like :, \\, /, ?, *, [, ]
invalid_chars = [':', '\\', '/', '?', '*', '[', ']']
for char in invalid_chars:
categ_name = categ_name.replace(char, ' ')
if categ_name not in lines_by_category:
lines_by_category[categ_name] = []
lines_by_category[categ_name].append(line)
if not lines_by_category:
raise UserError(_("There are no order lines to export."))
for categ_name, lines in lines_by_category.items():
sheet = workbook.add_worksheet(categ_name)
for col_num, header in enumerate(headers):
sheet.write(0, col_num, header, header_format)
row_num = 1
for line in lines:
item_type = "Item"
# Check custom field x_studio_bc_item_id on product
if 'x_studio_bc_item_id' in line.product_id._fields and line.product_id.x_studio_bc_item_id:
item_no = line.product_id.x_studio_bc_item_id
else:
item_no = ''
description = line.product_id.name or line.name or ''
qty = line.product_qty
# Determine packaging or unit
if 'product_packaging_id' in line._fields and line.product_packaging_id:
satuan = line.product_packaging_id.name
else:
satuan = line.product_uom_id.name or ''
sheet.write(row_num, 0, item_type)
sheet.write(row_num, 1, item_no)
sheet.write(row_num, 2, description)
sheet.write(row_num, 3, qty)
sheet.write(row_num, 4, satuan)
row_num += 1
workbook.close()
output.seek(0)
attachment_name = f"PO_Export_BC_{self.name.replace('/', '_')}.xlsx"
attachment = self.env['ir.attachment'].create({
'name': attachment_name,
'type': 'binary',
'datas': base64.b64encode(output.read()),
'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
return {
'type': 'ir.actions.act_url',
'url': f'/web/content/{attachment.id}?download=true',
'target': 'self',
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_purchase_order_form_inherit_export_bc" model="ir.ui.view">
<field name="name">purchase.order.form.inherit.export.bc</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//header" position="inside">
<button name="action_export_bc" string="Export PO to BC Format" type="object" class="oe_highlight" invisible="state not in ('purchase', 'done')"/>
</xpath>
</field>
</record>
</odoo>