summaryrefslogtreecommitdiff
path: root/fixco_custom/models/upload_bills.py
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2025-07-18 09:25:57 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2025-07-18 09:25:57 +0700
commit10e171ea5389873fea3fb13c90242b322a37a990 (patch)
tree9288e4c9693cb5ea1a3d18e66e0bb723f9be5133 /fixco_custom/models/upload_bills.py
parent66b6b5863a15377c91300079026b11e7f81d60e4 (diff)
On change product otomatis terisi di requisition
Create bills by search PO & SKU Create bills by upload
Diffstat (limited to 'fixco_custom/models/upload_bills.py')
-rw-r--r--fixco_custom/models/upload_bills.py195
1 files changed, 195 insertions, 0 deletions
diff --git a/fixco_custom/models/upload_bills.py b/fixco_custom/models/upload_bills.py
new file mode 100644
index 0000000..0c037f3
--- /dev/null
+++ b/fixco_custom/models/upload_bills.py
@@ -0,0 +1,195 @@
+from odoo import models, fields, api, _
+from datetime import datetime
+import base64
+import xlrd
+from odoo.exceptions import ValidationError, UserError
+import requests
+import json
+import hmac
+from hashlib import sha256
+
+class UploadBills(models.Model):
+ _name = "upload.bills"
+ _description = "Upload Bills"
+ _order = "create_date desc"
+ _rec_name = "number"
+
+ bills_lines = fields.One2many('upload.bills.line', 'upload_bills_id',
+ string='Lines', copy=False, auto_join=True)
+ number = fields.Char('Number', copy=False)
+ date_upload = fields.Datetime('Upload Date', copy=False)
+ user_id = fields.Many2one('res.users', 'Created By', default=lambda self: self.env.user.id)
+ excel_file = fields.Binary('Excel File', attachment=True)
+ filename = fields.Char('File Name')
+
+ @api.model
+ def create(self, vals):
+ vals['number'] = self.env['ir.sequence'].next_by_code('upload.bills') or '/'
+ return super().create(vals)
+
+ def action_import_excel(self):
+ self.ensure_one()
+ if not self.excel_file:
+ raise ValidationError(_("Please upload an Excel file first."))
+
+ try:
+ file_content = base64.b64decode(self.excel_file)
+ workbook = xlrd.open_workbook(file_contents=file_content)
+ sheet = workbook.sheet_by_index(0)
+ except Exception:
+ raise ValidationError(_("Invalid Excel file format."))
+
+ if sheet.ncols < 3:
+ raise ValidationError(_("Excel format tidak valid. Minimal ada 3 kolom: No BU IN, Tanggal, dan Faktur Pajak."))
+
+ rows_data = []
+ for row_idx in range(sheet.nrows):
+ try:
+ no_bu = str(sheet.cell(row_idx, 0).value).strip()
+ tanggal_raw = sheet.cell(row_idx, 1).value
+ faktur_pajak = str(sheet.cell(row_idx, 2).value).strip()
+
+ if isinstance(tanggal_raw, float):
+ tanggal = datetime(*xlrd.xldate_as_tuple(tanggal_raw, workbook.datemode)).date()
+ else:
+ tanggal = datetime.strptime(tanggal_raw, '%Y-%m-%d').date()
+
+ rows_data.append({
+ 'row_num': row_idx + 1,
+ 'no_bu': no_bu,
+ 'date': tanggal,
+ 'faktur_pajak': faktur_pajak,
+ })
+ except Exception:
+ continue
+
+ faktur_list = [row['faktur_pajak'] for row in rows_data]
+ existing_faktur = set()
+ no_bu_list = [row['no_bu'] for row in rows_data]
+ existing_no_bu = set()
+
+ chunk_size = 500
+ for i in range(0, len(faktur_list), chunk_size):
+ chunk_faktur = faktur_list[i:i + chunk_size]
+ chunk_no_bu = no_bu_list[i:i + chunk_size]
+
+ existing_lines = self.env['upload.bills.line'].search([
+ '|',
+ ('faktur_pajak', 'in', chunk_faktur),
+ ('no_bu', 'in', chunk_no_bu)
+ ])
+
+ existing_faktur.update(existing_lines.mapped('faktur_pajak'))
+ existing_no_bu.update(existing_lines.mapped('no_bu'))
+
+ duplicate_rows = []
+ for row in rows_data:
+ if row['faktur_pajak'] in existing_faktur or row['no_bu'] in existing_no_bu:
+ duplicate_rows.append(str(row['row_num']))
+
+ if duplicate_rows:
+ raise ValidationError(_("Data duplikat ditemukan di baris: %s\nPeriksa 'No BU IN' atau 'Faktur Pajak' yang sudah pernah diupload.") % ", ".join(duplicate_rows))
+
+ line_vals_list = []
+ for row in rows_data:
+ line_vals = {
+ 'no_bu': row['no_bu'],
+ 'date': row['date'],
+ 'faktur_pajak': row['faktur_pajak'],
+ 'upload_bills_id': self.id,
+ }
+ line_vals_list.append((0, 0, line_vals))
+
+ self.bills_lines.unlink()
+ self.write({'bills_lines': line_vals_list})
+
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': _('Success'),
+ 'message': _('Berhasil mengimpor %s baris dari Excel.') % len(line_vals_list),
+ 'sticky': False,
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ }
+
+
+ def _show_notification(self, message):
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': _('Success'),
+ 'message': message,
+ 'sticky': False,
+ }
+ }
+
+ def action_create_bills(self):
+ all_invoice_ids = []
+
+ for line in self.bills_lines:
+ bu_in = self.env['stock.picking'].search([
+ ('name', '=', line.no_bu),
+ ('picking_type_code', '=', 'incoming')
+ ], limit=1)
+
+ if not bu_in:
+ raise UserError(f"BU IN '{line.no_bu}' tidak ditemukan.")
+
+ # Panggil pembuatan invoice
+ created_invoices = bu_in.action_create_invoice_from_mr()
+
+ # Sinkron faktur dan tanggal ke account.move
+ if isinstance(created_invoices, dict) and 'res_id' in created_invoices:
+ # Satu invoice
+ invoice = self.env['account.move'].browse(created_invoices['res_id'])
+ invoice.write({
+ 'faktur_pajak': line.faktur_pajak,
+ 'invoice_date': line.date
+ })
+ invoice.action_post()
+ all_invoice_ids.append(invoice.id)
+
+ elif isinstance(created_invoices, dict) and 'domain' in created_invoices:
+ # Banyak invoice
+ invoice_ids = created_invoices.get('domain', [])[0][2] or []
+ invoices = self.env['account.move'].browse(invoice_ids)
+ invoices.write({
+ 'faktur_pajak': line.faktur_pajak,
+ 'invoice_date': line.date
+ })
+ invoices.action_post()
+ all_invoice_ids.extend(invoices.ids)
+
+ else:
+ raise UserError("Gagal menemukan invoice yang baru dibuat.")
+
+ # Tampilkan invoice(s) ke user
+ if not all_invoice_ids:
+ return {'type': 'ir.actions.act_window_close'}
+
+ action = self.env.ref('account.action_move_in_invoice_type').read()[0]
+ if len(all_invoice_ids) == 1:
+ action.update({
+ 'view_mode': 'tree,form',
+ 'res_id': all_invoice_ids,
+ })
+ else:
+ action.update({
+ 'domain': [('id', 'in', all_invoice_ids)],
+ 'view_mode': 'tree,form',
+ })
+ return action
+
+
+class UploadBillsLine(models.Model):
+ _name = "upload.bills.line"
+ _description = "Upload Bills Line"
+ _inherit = ['mail.thread']
+
+ upload_bills_id = fields.Many2one('upload.bills', string='Upload')
+ no_bu = fields.Char('No BU IN')
+ date = fields.Date('Date')
+ faktur_pajak = fields.Char('Faktur Pajak')