diff options
Diffstat (limited to 'fixco_custom')
| -rw-r--r-- | fixco_custom/__manifest__.py | 3 | ||||
| -rw-r--r-- | fixco_custom/models/__init__.py | 2 | ||||
| -rw-r--r-- | fixco_custom/models/barcoding_product.py | 78 | ||||
| -rw-r--r-- | fixco_custom/models/detail_order.py | 183 | ||||
| -rw-r--r-- | fixco_custom/models/product_product.py | 41 | ||||
| -rw-r--r-- | fixco_custom/models/sale.py | 1 | ||||
| -rw-r--r-- | fixco_custom/models/stock_picking.py | 278 | ||||
| -rw-r--r-- | fixco_custom/security/ir.model.access.csv | 6 | ||||
| -rw-r--r-- | fixco_custom/views/barcoding_product.xml | 78 | ||||
| -rw-r--r-- | fixco_custom/views/product_product.xml | 17 | ||||
| -rw-r--r-- | fixco_custom/views/sale_order.xml | 3 | ||||
| -rw-r--r-- | fixco_custom/views/stock_picking.xml | 47 |
12 files changed, 645 insertions, 92 deletions
diff --git a/fixco_custom/__manifest__.py b/fixco_custom/__manifest__.py index 232d2d9..85d9be3 100644 --- a/fixco_custom/__manifest__.py +++ b/fixco_custom/__manifest__.py @@ -15,6 +15,9 @@ 'views/sale_order.xml', 'views/webhook_ginee.xml', 'views/detail_order.xml', + 'views/stock_picking.xml', + 'views/product_product.xml', + 'views/barcoding_product.xml', ], 'demo': [], 'css': [], diff --git a/fixco_custom/models/__init__.py b/fixco_custom/models/__init__.py index 9b3459e..6a4717c 100644 --- a/fixco_custom/models/__init__.py +++ b/fixco_custom/models/__init__.py @@ -3,3 +3,5 @@ from . import sale from . import webhook_ginee from . import detail_order from . import stock_picking +from . import product_product +from . import barcoding_product diff --git a/fixco_custom/models/barcoding_product.py b/fixco_custom/models/barcoding_product.py new file mode 100644 index 0000000..335b481 --- /dev/null +++ b/fixco_custom/models/barcoding_product.py @@ -0,0 +1,78 @@ +from odoo import models, api, fields +from odoo.exceptions import AccessError, UserError, ValidationError +from datetime import timedelta, date, datetime +import logging + +_logger = logging.getLogger(__name__) + +class BarcodingProduct(models.Model): + _name = "barcoding.product" + _description = "Barcoding Product" + + barcoding_product_line = fields.One2many('barcoding.product.line', 'barcoding_product_id', string='Barcoding Product Lines', auto_join=True) + product_id = fields.Many2one('product.product', string="Product", tracking=3) + quantity = fields.Float(string="Quantity", tracking=3) + type = fields.Selection([('print', 'Print Barcode'), ('barcoding', 'Add Barcode To Product'), ('barcoding_box', 'Add Barcode Box To Product'), ('multiparts', 'Multiparts Product')], string='Type', default='print') + barcode = fields.Char(string="Barcode") + qty_pcs_box = fields.Char(string="Quantity Pcs Box") + + def check_duplicate_barcode(self): + if self.type in ['barcoding_box', 'barcoding']: + barcode_product = self.env['product.product'].search([('barcode', '=', self.barcode)]) + + if barcode_product: + raise UserError('Barcode sudah digunakan {}'.format(barcode_product.display_name)) + + barcode_box = self.env['product.product'].search([('barcode_box', '=', self.barcode)]) + + if barcode_box: + raise UserError('Barcode box sudah digunakan {}'.format(barcode_box.display_name)) + + @api.constrains('barcode') + def _send_barcode_to_product(self): + for record in self: + record.check_duplicate_barcode() + if record.type == 'barcoding_box': + record.product_id.barcode_box = record.barcode + record.product_id.qty_pcs_box = record.qty_pcs_box + else: + record.product_id.barcode = record.barcode + + @api.onchange('product_id', 'quantity') + def _onchange_product_or_quantity(self): + if self.product_id and self.quantity > 0: + self.barcoding_product_line = [(5, 0, 0)] + + lines = [] + for i in range(int(self.quantity)): + lines.append((0, 0, { + 'product_id': self.product_id.id, + 'barcoding_product_id': self.id, + 'sequence_with_total': f"{i+1}/{int(self.quantity)}" + })) + self.barcoding_product_line = lines + + def write(self, vals): + res = super().write(vals) + if 'quantity' in vals and self.type == 'multiparts': + self._update_sequence_with_total() + return res + + def _update_sequence_with_total(self): + for rec in self: + total = int(rec.quantity) + for index, line in enumerate(rec.barcoding_product_line, start=1): + line.sequence_with_total = f"{index}/{total}" + + +class BarcodingProductLine(models.Model): + _name = 'barcoding.product.line' + _description = 'Barcoding Product Line' + _order = 'barcoding_product_id, id' + + barcoding_product_id = fields.Many2one('barcoding.product', string='Barcoding Product Ref', required=True, ondelete='cascade', index=True, copy=False) + product_id = fields.Many2one('product.product', string="Product") + qr_code_variant = fields.Binary("QR Code Variant", related='product_id.qr_code_variant') + sequence_with_total = fields.Char( + string="Sequence" + )
\ No newline at end of file diff --git a/fixco_custom/models/detail_order.py b/fixco_custom/models/detail_order.py index 7bb3aec..466544f 100644 --- a/fixco_custom/models/detail_order.py +++ b/fixco_custom/models/detail_order.py @@ -23,6 +23,7 @@ class DetailOrder(models.Model): ('so_confirm', 'SO Confirm'), ('done', 'Done'), ('failed', 'Failed'), + ('already_so', 'SO Already Created'), ], 'Execute Status') sale_id = fields.Many2one('sale.order', 'Sale Order') picking_id = fields.Many2one('stock.picking', 'Picking') @@ -83,8 +84,7 @@ class DetailOrder(models.Model): self.execute_status = 'detail_order' else: self.write({ - 'execute_status': 'failed', - 'json_ginee': json.dumps({ + 'message_error': json.dumps({ 'error': f"Request failed with status code {response.status_code}", 'response': response.text }) @@ -92,8 +92,7 @@ class DetailOrder(models.Model): except Exception as e: self.write({ - 'execute_status': 'failed', - 'json_ginee': json.dumps({ + 'message_error': json.dumps({ 'error': str(e) }) }) @@ -143,7 +142,11 @@ class DetailOrder(models.Model): limit=1 ) if not product: - raise UserError(_("Product not found for SKU: %s") % item.get('sku')) + product = self.env['product.product'].search( + [('default_code', '=', 'PL-LN0760')], + limit=1 + ) + # raise UserError(_("Product not found for SKU: %s") % item.get('sku')) line_data = { 'product_id': product.id, @@ -161,35 +164,43 @@ class DetailOrder(models.Model): order_lines = self.prepare_data_so_line(json_data) order_id, order_status, print_info = self.get_order_id_detail() - if order_status == 'READY_TO_SHIP' and print_info == 'NOT_PRINTED': - # if order_status == 'SHIPPING' and print_info == 'PRINTED': - data['order_line'] = order_lines - - sale_order = self.env['sale.order'].create(data) - - self.sale_id = sale_order.id - sale_order.action_confirm() + if order_status != 'PENDING_PAYMENT': + if order_status == 'PARTIALLY_PAID' or order_status == 'PAID': + data['order_line'] = order_lines + + sale_order = self.env['sale.order'].create(data) + + self.sale_id = sale_order.id + sale_order.order_reference = order_id + sale_order.action_confirm() + - self.picking_id = sale_order.picking_ids[0].id + self.picking_id = sale_order.picking_ids[0].id - self.execute_status = 'so_confirm' - elif order_status == 'READY_TO_SHIP' and print_info == 'PRINTED': - data['order_line'] = order_lines - - sale_order = self.env['sale.order'].create(data) - - self.sale_id = sale_order.id - sale_order.action_confirm() + self.picking_id.order_reference = order_id - self.picking_id = sale_order.picking_ids[0].id - self.picking_id.sync_qty_reserved_qty_done() + self.execute_status = 'so_confirm' + else: + sale_orders = self.env['sale.order'].search([('order_reference', '=', order_id)]) + if not sale_orders: + data['order_line'] = order_lines + + sale_order = self.env['sale.order'].create(data) + + self.sale_id = sale_order.id + sale_order.order_reference = order_id + sale_order.action_confirm() - self.execute_status = 'so_confirm' - + self.picking_id = sale_order.picking_ids[0].id + self.picking_id.order_reference = order_id + + self.execute_status = 'so_confirm' + else: + self.sale_id = sale_orders.id + self.execute_status = 'already_so' except Exception as e: self.write({ - 'execute_status': 'failed', 'message_error': json.dumps({ 'error': str(e) }) @@ -206,72 +217,72 @@ class DetailOrder(models.Model): # check print do section - def get_order_id_check_print(self): - try: - if self.detail_order: - json_data = json.loads(self.detail_order) - order_id = json_data.get('data', {})[0].get('orderId') - if not order_id: - raise UserError(_("Order ID not found in JSON data")) - return order_id - raise UserError(_("No JSON data available")) - except json.JSONDecodeError: - raise UserError(_("Invalid JSON format in check_print field")) - except Exception as e: - raise UserError(_("Error extracting order ID: %s") % str(e)) + # def get_order_id_check_print(self): + # try: + # if self.detail_order: + # json_data = json.loads(self.detail_order) + # order_id = json_data.get('data', {})[0].get('orderId') + # if not order_id: + # raise UserError(_("Order ID not found in JSON data")) + # return order_id + # raise UserError(_("No JSON data available")) + # except json.JSONDecodeError: + # raise UserError(_("Invalid JSON format in check_print field")) + # except Exception as e: + # raise UserError(_("Error extracting order ID: %s") % str(e)) - def process_queue_item_check_print(self, limit=100): - domain = [('picking_id.state', 'not in', ['done', 'cancel'])] - records = self.search(domain, order='create_date asc', limit=limit) - for rec in records: - rec.execute_queue_check_print() + # def process_queue_item_check_print(self, limit=100): + # domain = [('picking_id.state', 'not in', ['done', 'cancel'])] + # records = self.search(domain, order='create_date asc', limit=limit) + # for rec in records: + # rec.execute_queue_check_print() - def execute_queue_check_print(self): - try: - order_id = self.get_order_id_check_print() + # def execute_queue_check_print(self): + # try: + # order_id = self.get_order_id_check_print() - authorization = self.sign_request() - headers = { - 'Content-Type': 'application/json', - 'X-Advai-Country': 'ID', - 'Authorization': authorization - } + # authorization = self.sign_request() + # headers = { + # 'Content-Type': 'application/json', + # 'X-Advai-Country': 'ID', + # 'Authorization': authorization + # } - payload = { - "orderIds": [order_id] - } + # payload = { + # "orderIds": [order_id] + # } - url = "https://api.ginee.com/openapi/order/v1/batch-get" + # url = "https://api.ginee.com/openapi/order/v1/batch-get" - response = requests.post( - url, - headers=headers, - data=json.dumps(payload) - ) + # response = requests.post( + # url, + # headers=headers, + # data=json.dumps(payload) + # ) - if response.status_code == 200: - data = response.json() - self.detail_order = json.dumps(data) - detail_order = json.loads(self.detail_order) - if detail_order['data'][0]['printInfo']['labelPrintStatus'] == 'PRINTED': #ubah ke printed lagi nanti - self.picking_id.sync_qty_reserved_qty_done() - # self.sale_id.api_create_invoices(self.sale_id.id) - self.execute_status = 'done' - else: - self.write({ - 'execute_status': 'failed', - 'json_ginee': json.dumps({ - 'error': f"Request failed with status code {response.status_code}", - 'response': response.text - }) - }) + # if response.status_code == 200: + # data = response.json() + # self.detail_order = json.dumps(data) + # detail_order = json.loads(self.detail_order) + # if detail_order['data'][0]['printInfo']['labelPrintStatus'] == 'PRINTED': #ubah ke printed lagi nanti + # self.picking_id.sync_qty_reserved_qty_done() + # # self.sale_id.api_create_invoices(self.sale_id.id) + # self.execute_status = 'done' + # else: + # self.write({ + # 'execute_status': 'failed', + # 'json_ginee': json.dumps({ + # 'error': f"Request failed with status code {response.status_code}", + # 'response': response.text + # }) + # }) - except Exception as e: - self.write({ - 'execute_status': 'failed', - 'json_ginee': json.dumps({ - 'error': str(e) - }) - }) + # except Exception as e: + # self.write({ + # 'execute_status': 'failed', + # 'json_ginee': json.dumps({ + # 'error': str(e) + # }) + # })
\ No newline at end of file diff --git a/fixco_custom/models/product_product.py b/fixco_custom/models/product_product.py new file mode 100644 index 0000000..2e571a8 --- /dev/null +++ b/fixco_custom/models/product_product.py @@ -0,0 +1,41 @@ +from odoo import fields, models, api, tools, _ +from datetime import datetime, timedelta, date +from odoo.exceptions import UserError +import logging +import requests +import json +import re +import qrcode, base64 +from bs4 import BeautifulSoup +from io import BytesIO + + +class ProductProduct(models.Model): + _inherit = "product.product" + + qty_pcs_box = fields.Float("Pcs Box") + barcode_box = fields.Char("Barcode Box") + qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant') + + def _compute_qr_code_variant(self): + for rec in self: + # Skip inactive variants + if not rec.active: + rec.qr_code_variant = False # Clear the QR Code for archived variants + continue + + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=5, + border=4, + ) + qr.add_data(rec.barcode if rec.barcode else rec.default_code) + qr.make(fit=True) + img = qr.make_image(fill_color="black", back_color="white") + + buffer = BytesIO() + img.save(buffer, format="PNG") + qr_code_img = base64.b64encode(buffer.getvalue()).decode() + + rec.qr_code_variant = qr_code_img
\ No newline at end of file diff --git a/fixco_custom/models/sale.py b/fixco_custom/models/sale.py index b266d6a..8764681 100644 --- a/fixco_custom/models/sale.py +++ b/fixco_custom/models/sale.py @@ -6,3 +6,4 @@ class SaleOrder(models.Model): _inherit = "sale.order" carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method') + order_reference = fields.Char(string='Order Reference') diff --git a/fixco_custom/models/stock_picking.py b/fixco_custom/models/stock_picking.py index 4814ac5..9e2a5e6 100644 --- a/fixco_custom/models/stock_picking.py +++ b/fixco_custom/models/stock_picking.py @@ -15,18 +15,286 @@ import requests import time import logging import re +from hashlib import sha256 _logger = logging.getLogger(__name__) +Request_URI = '/openapi/order/v1/print' +ACCESS_KEY = '24bb6a1ec618ec6a' +SECRET_KEY = '32e4a78ad05ee230' class StockPicking(models.Model): _inherit = 'stock.picking' + check_product_lines = fields.One2many('check.product', 'picking_id', string='Check Product', auto_join=True, copy=False) - def sync_qty_reserved_qty_done(self): + order_reference = fields.Char('Order Reference') + provider_name = fields.Char('Provider Name') + tracking_number = fields.Char('Tracking Number') + invoice_number = fields.Char('Invoice Number') + pdf_label_url = fields.Char('PDF Label URL') + + def label_ginee(self): + try: + order_id = self.order_reference + + authorization = self.sign_request() + headers = { + 'Content-Type': 'application/json', + 'X-Advai-Country': 'ID', + 'Authorization': authorization + } + + payload = { + "orderId": order_id, + "documentType": "LABEL" + } + url = "https://api.ginee.com/openapi/order/v1/print" + + response = requests.post( + url, + headers=headers, + data=json.dumps(payload) + ) + + if response.status_code == 200: + data = response.json() + if data.get('code') == 'SUCCESS' and data.get('message') == 'OK': + logistic_info_list = data.get('data', {}).get('logisticsInfos') + + # Check if logistic_info exists and has at least one item + if not logistic_info_list: + raise UserError(_("No logistic information found in response")) + + logistic_info = logistic_info_list[0] + self.pdf_label_url = data.get('data', {}).get('pdfUrl') or '' + self.tracking_number = logistic_info.get('logisticsTrackingNumber') or '' + self.provider_name = logistic_info.get('logisticsProviderName') or '' + self.invoice_number = logistic_info.get('invoiceNumber') or '' + else: + raise UserError(_("API Error: %s - %s") % (data.get('code', 'UNKNOWN'), data.get('message', 'No error message'))) + else: + raise UserError(_("API request failed with status code: %s") % response.status_code) + + except Exception as e: + raise UserError(_("Error: %s") % str(e)) + + def sign_request(self): + signData = '$'.join(['POST', Request_URI]) + '$' + authorization = ACCESS_KEY + ':' + base64.b64encode( + hmac.new(SECRET_KEY.encode('utf-8'), signData.encode('utf-8'), digestmod=sha256).digest() + ).decode('ascii') + return authorization + + + + # def sync_qty_reserved_qty_done(self): - for picking in self: - for line in picking.move_line_ids_without_package: - line.qty_done = line.product_uom_qty + # for picking in self: + # for line in picking.move_line_ids_without_package: + # line.qty_done = line.product_uom_qty - picking.button_validate()
\ No newline at end of file + # picking.button_validate() + +class CheckProduct(models.Model): + _name = 'check.product' + _description = 'Check Product' + _order = 'picking_id, id' + + picking_id = fields.Many2one( + 'stock.picking', + string='Picking Reference', + required=True, + ondelete='cascade', + index=True, + copy=False, + ) + product_id = fields.Many2one('product.product', string='Product') + quantity = fields.Float(string='Quantity') + status = fields.Char(string='Status', compute='_compute_status') + code_product = fields.Char(string='Code Product') + + @api.onchange('code_product') + def _onchange_code_product(self): + if not self.code_product: + return + + # Cari product berdasarkan default_code, barcode, atau barcode_box + product = self.env['product.product'].search([ + '|', + ('default_code', '=', self.code_product), + '|', + ('barcode', '=', self.code_product), + ('barcode_box', '=', self.code_product) + ], limit=1) + + if not product: + raise UserError("Product tidak ditemukan") + + # Jika scan barcode_box, set quantity sesuai qty_pcs_box + if product.barcode_box == self.code_product: + self.product_id = product.id + self.quantity = product.qty_pcs_box + self.code_product = product.default_code or product.barcode + # return { + # 'warning': { + # 'title': 'Info',8994175025871 + + # 'message': f'Product box terdeteksi. Quantity di-set ke {product.qty_pcs_box}' + # } + # } + else: + # Jika scan biasa + self.product_id = product.id + self.code_product = product.default_code or product.barcode + self.quantity = 1 + + def unlink(self): + # Get all affected pickings before deletion + pickings = self.mapped('picking_id') + + # Store product_ids that will be deleted + deleted_product_ids = self.mapped('product_id') + + # Perform the deletion + result = super(CheckProduct, self).unlink() + + # After deletion, update moves for affected pickings + for picking in pickings: + # For products that were completely removed (no remaining check.product lines) + remaining_product_ids = picking.check_product_lines.mapped('product_id') + removed_product_ids = deleted_product_ids - remaining_product_ids + + # Set quantity_done to 0 for moves of completely removed products + moves_to_reset = picking.move_ids_without_package.filtered( + lambda move: move.product_id in removed_product_ids + ) + for move in moves_to_reset: + move.quantity_done = 0.0 + + # Also sync remaining products in case their totals changed + self._sync_check_product_to_moves(picking) + + return result + + @api.depends('quantity') + def _compute_status(self): + for record in self: + moves = record.picking_id.move_ids_without_package.filtered( + lambda move: move.product_id.id == record.product_id.id + ) + total_qty_in_moves = sum(moves.mapped('product_uom_qty')) + + if record.quantity < total_qty_in_moves: + record.status = 'Pending' + else: + record.status = 'Done' + + def create(self, vals): + # Create the record + record = super(CheckProduct, self).create(vals) + # Ensure uniqueness after creation + if not self.env.context.get('skip_consolidate'): + record.with_context(skip_consolidate=True)._consolidate_duplicate_lines() + return record + + def write(self, vals): + # Write changes to the record + result = super(CheckProduct, self).write(vals) + # Ensure uniqueness after writing + if not self.env.context.get('skip_consolidate'): + self.with_context(skip_consolidate=True)._consolidate_duplicate_lines() + return result + + def _sync_check_product_to_moves(self, picking): + """ + Sinkronisasi quantity_done di move_ids_without_package + dengan total quantity dari check.product berdasarkan product_id. + """ + for product_id in picking.check_product_lines.mapped('product_id'): + # Totalkan quantity dari semua baris check.product untuk product_id ini + total_quantity = sum( + line.quantity for line in + picking.check_product_lines.filtered(lambda line: line.product_id == product_id) + ) + # Update quantity_done di move yang relevan + moves = picking.move_ids_without_package.filtered(lambda move: move.product_id == product_id) + for move in moves: + move.quantity_done = total_quantity + + def _consolidate_duplicate_lines(self): + """ + Consolidate duplicate lines with the same product_id under the same picking_id + and sync the total quantity to related moves. + """ + for picking in self.mapped('picking_id'): + lines_to_remove = self.env['check.product'] # Recordset untuk menyimpan baris yang akan dihapus + product_lines = picking.check_product_lines.filtered(lambda line: line.product_id) + + # Group lines by product_id + product_groups = {} + for line in product_lines: + product_groups.setdefault(line.product_id.id, []).append(line) + + for product_id, lines in product_groups.items(): + if len(lines) > 1: + # Consolidate duplicate lines + first_line = lines[0] + total_quantity = sum(line.quantity for line in lines) + + # Update the first line's quantity + first_line.with_context(skip_consolidate=True).write({'quantity': total_quantity}) + + # Add the remaining lines to the lines_to_remove recordset + lines_to_remove |= self.env['check.product'].browse([line.id for line in lines[1:]]) + + # Perform unlink after consolidation + if lines_to_remove: + lines_to_remove.unlink() + + # Sync total quantities to moves + self._sync_check_product_to_moves(picking) + + @api.onchange('product_id', 'quantity') + def check_product_validity(self): + for record in self: + if not record.picking_id or not record.product_id: + continue + + # Filter moves related to the selected product + moves = record.picking_id.move_ids_without_package.filtered( + lambda move: move.product_id.id == record.product_id.id + ) + + if not moves: + raise UserError(( + "The product '%s' tidak ada di operations. " + ) % record.product_id.display_name) + + total_qty_in_moves = sum(moves.mapped('product_uom_qty')) + + # Find existing lines for the same product, excluding the current line + existing_lines = record.picking_id.check_product_lines.filtered( + lambda line: line.product_id == record.product_id + ) + + if existing_lines: + # Get the first existing line + first_line = existing_lines[0] + + # Calculate the total quantity after addition + total_quantity = sum(existing_lines.mapped('quantity')) + + if total_quantity > total_qty_in_moves: + raise UserError(( + "Quantity Product '%s' sudah melebihi quantity demand." + ) % (record.product_id.display_name)) + else: + # Check if the quantity exceeds the allowed total + if record.quantity == total_qty_in_moves: + raise UserError(( + "Quantity Product '%s' sudah melebihi quantity demand." + ) % (record.product_id.display_name)) + + # Set the quantity to the entered value + record.quantity = record.quantity
\ No newline at end of file diff --git a/fixco_custom/security/ir.model.access.csv b/fixco_custom/security/ir.model.access.csv index a2d897a..260397e 100644 --- a/fixco_custom/security/ir.model.access.csv +++ b/fixco_custom/security/ir.model.access.csv @@ -1,3 +1,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_webhook_ginee,access.webhook.ginee,model_webhook_ginee,,1,1,1,1 -access_detail_order,access.detail.order,model_detail_order,,1,1,1,1
\ No newline at end of file +access_detail_order,access.detail.order,model_detail_order,,1,1,1,1 +access_check_product,access.check.product,model_check_product,,1,1,1,1 +access_product_product,access.product.product,model_product_product,,1,1,1,1 +access_barcoding_product,access.barcoding.product,model_barcoding_product,,1,1,1,1 +access_barcoding_product_line,access.barcoding.product.line,model_barcoding_product_line,,1,1,1,1
\ No newline at end of file diff --git a/fixco_custom/views/barcoding_product.xml b/fixco_custom/views/barcoding_product.xml new file mode 100644 index 0000000..b259f1e --- /dev/null +++ b/fixco_custom/views/barcoding_product.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<odoo> + <data> + <record id="barcoding_product_tree" model="ir.ui.view"> + <field name="name">barcoding.product.tree</field> + <field name="model">barcoding.product</field> + <field name="arch" type="xml"> + <tree default_order="create_date desc"> + <field name="product_id"/> + <field name="quantity"/> + <field name="type"/> + </tree> + </field> + </record> + + <record id="barcoding_product_line_tree" model="ir.ui.view"> + <field name="name">barcoding.product.line.tree</field> + <field name="model">barcoding.product.line</field> + <field name="arch" type="xml"> + <tree> + <field name="product_id"/> + <field name="qr_code_variant" widget="image"/> + <field name="sequence_with_total" attrs="{'invisible': [['parent.type', 'not in', ('multiparts')]]}"/> + </tree> + </field> + </record> + + <record id="barcoding_product_form" model="ir.ui.view"> + <field name="name">barcoding.product.form</field> + <field name="model">barcoding.product</field> + <field name="arch" type="xml"> + <form > + <sheet> + <group> + <group> + <field name="product_id" required="1"/> + <field name="type" required="1"/> + <field name="quantity" attrs="{'invisible': [['type', 'in', ('barcoding','barcoding_box')]], 'required': [['type', 'not in', ('barcoding')]]}"/> + <field name="barcode" attrs="{'invisible': [['type', 'in', ('print','multiparts')]], 'required': [['type', 'not in', ('print','multiparts')]]}"/> + <field name="qty_pcs_box" attrs="{'invisible': [['type', 'in', ('print','barcoding','multiparts')]], 'required': [['type', 'not in', ('print','barcoding','multiparts')]]}"/> + </group> + </group> + <notebook> + <page string="Line" attrs="{'invisible': [['type', 'in', ('barcoding','barcoding_box')]]}"> + <field name="barcoding_product_line"/> + </page> + </notebook> + </sheet> + </form> + </field> + </record> + + <record id="barcoding_product_view_search" model="ir.ui.view"> + <field name="name">barcoding.product.search.view</field> + <field name="model">barcoding.product</field> + <field name="arch" type="xml"> + <search string="Search Barcoding Product"> + <field name="product_id"/> + </search> + </field> + </record> + + <record id="barcoding_product_action" model="ir.actions.act_window"> + <field name="name">Barcoding Product</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">barcoding.product</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem + id="menu_barcoding_product" + name="Barcoding Product" + parent="stock.menu_stock_warehouse_mgmt" + sequence="4" + action="barcoding_product_action" + /> + </data> +</odoo> diff --git a/fixco_custom/views/product_product.xml b/fixco_custom/views/product_product.xml new file mode 100644 index 0000000..2db7c31 --- /dev/null +++ b/fixco_custom/views/product_product.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <data> + <record id="product_normal_form_view_inherit" model="ir.ui.view"> + <field name="name">Product Template</field> + <field name="model">product.product</field> + <field name="inherit_id" ref="product.product_normal_form_view"/> + <field name="arch" type="xml"> + <field name="categ_id" position="after"> + <field name="barcode_box" /> + <field name="qty_pcs_box" /> + <field name="qr_code_variant" widget="image" readonly="True"/> + </field> + </field> + </record> + </data> +</odoo> diff --git a/fixco_custom/views/sale_order.xml b/fixco_custom/views/sale_order.xml index 5a6bcbf..cbcbdc2 100644 --- a/fixco_custom/views/sale_order.xml +++ b/fixco_custom/views/sale_order.xml @@ -9,6 +9,9 @@ <field name="tag_ids" position="after"> <field name="carrier_id"/> </field> + <field name="client_order_ref" position="after"> + <field name="order_reference"/> + </field> </field> </record> </data> diff --git a/fixco_custom/views/stock_picking.xml b/fixco_custom/views/stock_picking.xml new file mode 100644 index 0000000..17ed3e0 --- /dev/null +++ b/fixco_custom/views/stock_picking.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <data> + <record id="stock_picking_form_view_inherit" model="ir.ui.view"> + <field name="name">Stock Picking</field> + <field name="model">stock.picking</field> + <field name="inherit_id" ref="stock.view_picking_form"/> + <field name="arch" type="xml"> + <button name="action_confirm" position="before"> + <button name="label_ginee" + string="Print Label Ginee" + type="object" + /> + </button> + + <group name="other_infos" position="after"> + <group string="Shipping Information" name="shipping_infos"> + <field name="order_reference" readonly="1"/> + <field name="provider_name" readonly="1"/> + <field name="tracking_number" readonly="1"/> + <field name="invoice_number" readonly="1"/> + <field name="pdf_label_url" readonly="1" widget="url"/> + </group> + </group> + + <page name="note" position="after"> + <page string="Check Product" name="check_product"> + <field name="check_product_lines"/> + </page> + </page> + </field> + </record> + + <record id="check_product_tree" model="ir.ui.view"> + <field name="name">check.product.tree</field> + <field name="model">check.product</field> + <field name="arch" type="xml"> + <tree editable="bottom" decoration-warning="status == 'Pending'" decoration-success="status == 'Done'"> + <field name="code_product"/> + <field name="product_id"/> + <field name="quantity"/> + <field name="status" readonly="1"/> + </tree> + </field> + </record> + </data> +</odoo>
\ No newline at end of file |
