summaryrefslogtreecommitdiff
path: root/fixco_custom/models/upload_cancel_picking.py
diff options
context:
space:
mode:
Diffstat (limited to 'fixco_custom/models/upload_cancel_picking.py')
-rw-r--r--fixco_custom/models/upload_cancel_picking.py213
1 files changed, 213 insertions, 0 deletions
diff --git a/fixco_custom/models/upload_cancel_picking.py b/fixco_custom/models/upload_cancel_picking.py
new file mode 100644
index 0000000..a42ef1d
--- /dev/null
+++ b/fixco_custom/models/upload_cancel_picking.py
@@ -0,0 +1,213 @@
+from odoo import models, fields, api, _
+from datetime import datetime
+import base64
+import xlrd
+from odoo.exceptions import ValidationError
+
+
+class UploadCancelPicking(models.Model):
+ _name = "upload.cancel.picking"
+ _description = "Upload Cancel Picking"
+ _order = "create_date desc"
+ _rec_name = "number"
+
+ picking_lines = fields.One2many(
+ 'upload.cancel.picking.line',
+ 'upload_cancel_picking_id',
+ string='Lines',
+ copy=False
+ )
+ number = fields.Char('Number', copy=False)
+ date_upload = fields.Datetime('Cancel Date', copy=False)
+ user_id = fields.Many2one(
+ 'res.users',
+ 'Created By',
+ default=lambda self: self.env.user
+ )
+ 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.cancel.picking'
+ ) 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."))
+
+ # === Load Excel ===
+ 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."))
+
+ # === Validate Header ===
+ header = [
+ str(sheet.cell(0, col).value).strip().lower()
+ for col in range(sheet.ncols)
+ ]
+
+ if 'invoice' not in header:
+ raise ValidationError(
+ _("Invalid Excel format. Expected column: Invoice")
+ )
+
+ invoice_col = header.index('invoice')
+
+ # === Read Rows ===
+ rows_data = []
+ for row_idx in range(1, sheet.nrows):
+ invoice_marketplace = str(
+ sheet.cell(row_idx, invoice_col).value
+ ).strip()
+
+ if not invoice_marketplace:
+ raise ValidationError(
+ _("Invoice kosong di baris Excel %s") % (row_idx + 1)
+ )
+
+ rows_data.append((row_idx + 1, invoice_marketplace))
+
+ if not rows_data:
+ raise ValidationError(_("Excel tidak berisi data."))
+
+ # === Validate Duplicate in Excel ===
+ seen = set()
+ duplicate_excel_rows = []
+
+ for row_num, invoice_marketplace in rows_data:
+ if invoice_marketplace in seen:
+ duplicate_excel_rows.append(str(row_num))
+ seen.add(invoice_marketplace)
+
+ if duplicate_excel_rows:
+ raise ValidationError(
+ _("Duplicate Invoice di file Excel pada baris: %s")
+ % ", ".join(duplicate_excel_rows)
+ )
+
+ # === Validate Duplicate in System ===
+ invoice_to_check = [inv for _, inv in rows_data]
+ existing_invoices = set()
+
+ chunk_size = 500
+ for i in range(0, len(invoice_to_check), chunk_size):
+ chunk = invoice_to_check[i:i + chunk_size]
+ records = self.env['upload.cancel.picking.line'].search([
+ ('invoice_marketplace', 'in', chunk)
+ ])
+ existing_invoices.update(records.mapped('invoice_marketplace'))
+
+ duplicate_system_rows = []
+ for row_num, invoice_marketplace in rows_data:
+ if invoice_marketplace in existing_invoices:
+ duplicate_system_rows.append(str(row_num))
+
+ if duplicate_system_rows:
+ raise ValidationError(
+ _("Invoice Marketplace sudah ada di sistem. "
+ "Ditemukan di baris: %s")
+ % ", ".join(duplicate_system_rows)
+ )
+
+ # === Create Lines ===
+ line_vals = [
+ (0, 0, {
+ 'invoice_marketplace': invoice_marketplace,
+ 'upload_cancel_picking_id': self.id,
+ })
+ for _, invoice_marketplace in rows_data
+ ]
+
+ # Clear old lines (safe way)
+ self.picking_lines = [(5, 0, 0)]
+ self.write({'picking_lines': line_vals})
+ self.picking_lines.get_order_id()
+
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': _('Success'),
+ 'message': _('Imported %s lines from Excel.')
+ % len(line_vals),
+ 'sticky': False,
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ }
+
+ def action_cancel_picking(self):
+ self.date_upload = datetime.utcnow()
+ self.picking_lines.cancel_picking()
+
+
+class UploadCancelPickingLine(models.Model):
+ _name = "upload.cancel.picking.line"
+ _description = "Upload Cancel Picking Line"
+ _inherit = ['mail.thread']
+
+ upload_cancel_picking_id = fields.Many2one(
+ 'upload.cancel.picking',
+ string='Upload'
+ )
+ invoice_marketplace = fields.Char(
+ 'Invoice Marketplace',
+ required=True
+ )
+ picking_id = fields.Many2one(
+ 'stock.picking',
+ 'Picking Reference'
+ )
+ status_picking = fields.Selection([
+ ('done', 'Done'),
+ ('cancel', 'Cancel'),
+ ('assigned', 'Ready'),
+ ('confirmed', 'Waiting'),
+ ('waiting', 'Waiting Another Operation'),
+ ], related='picking_id.state')
+ message_error = fields.Text('Error Message')
+ is_grouped = fields.Boolean('Is Grouped', default=False)
+ group_key = fields.Char('Group Key')
+
+
+ def get_order_id(self):
+ StockPicking = self.env['stock.picking']
+
+ invoices = self.mapped('invoice_marketplace')
+
+ if not invoices:
+ return
+
+ # Ambil semua picking yang matching invoice_mp
+ pickings = StockPicking.search([
+ ('invoice_mp', 'in', invoices)
+ ])
+
+ picking_map = {
+ p.invoice_mp: p.id
+ for p in pickings
+ if p.invoice_mp
+ }
+
+ for line in self:
+ picking_id = picking_map.get(line.invoice_marketplace)
+
+ if picking_id:
+ line.picking_id = picking_id
+ line.message_error = False
+ else:
+ line.picking_id = False
+ line.message_error = _(
+ "Stock Picking tidak ditemukan untuk invoice %s"
+ ) % line.invoice_marketplace
+
+ def cancel_picking(self):
+ for line in self:
+ line.picking_id.action_cancel() \ No newline at end of file