diff --git a/MKS_Tradex_Backend_2/__init__.py b/MKS_Tradex_Backend_2/__init__.py
new file mode 100755
index 0000000..d6210b1
--- /dev/null
+++ b/MKS_Tradex_Backend_2/__init__.py
@@ -0,0 +1,3 @@
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import models
diff --git a/MKS_Tradex_Backend_2/__manifest__.py b/MKS_Tradex_Backend_2/__manifest__.py
new file mode 100755
index 0000000..59710e6
--- /dev/null
+++ b/MKS_Tradex_Backend_2/__manifest__.py
@@ -0,0 +1,29 @@
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+{
+ 'name': 'MKS Tradex Backend',
+ 'version': '13.0.1.0',
+ 'category': 'Operations/Purchase',
+ 'description': """
+This module allows you to manage your Purchase Agreements flow.
+ Store keeper create Purchase Agreement
+ Purchase Codinator Approve / Reject Purchase Agreement
+ Purchase Manager Approve / Reject Purchase Agreement
+ Purchase Codinator Create RFQ after Approve purchase agreement by purchase manager
+
+""",
+ 'depends': ['purchase','purchase_requisition','sale_management'],
+ 'data': [
+ 'edi/mail_template.xml',
+ 'edi/purchase_mail_template.xml',
+ 'edi/sale_mail_template.xml',
+ 'edi/invoice_mail_template.xml',
+ 'security/purchase_security.xml',
+ 'security/account_security.xml',
+ 'views/purchase_requisition_views.xml',
+ 'views/purchase_order_views.xml',
+ 'views/sale_order_view.xml',
+ 'views/stock_picking.xml',
+ 'views/account_move_views.xml',
+ ],
+
+}
diff --git a/MKS_Tradex_Backend_2/edi/invoice_mail_template.xml b/MKS_Tradex_Backend_2/edi/invoice_mail_template.xml
new file mode 100755
index 0000000..0adda9e
--- /dev/null
+++ b/MKS_Tradex_Backend_2/edi/invoice_mail_template.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ Invoice Approval Email Temmplate
+ ${(object.user_id.email and '%s <%s>' % (object.user_id.company_id.name, object.user_id.email) or '')|safe}
+ Invoice Financial Approval
+
+
+
+ To Manager,
+ Please Approve Account Invoice Request bellow link
+
+
+ % set setup_url = object.make_invoice_url()
+
+ Approve Invoice Request
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/edi/mail_template.xml b/MKS_Tradex_Backend_2/edi/mail_template.xml
new file mode 100755
index 0000000..318949c
--- /dev/null
+++ b/MKS_Tradex_Backend_2/edi/mail_template.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+ Purchase Coordinator
+ ${(object.user_id.email and '%s <%s>' % (object.user_id.company_id.name, object.user_id.email) or '')|safe}
+ Purchase Agreements Approve
+
+
+
+ Dear Purchase Coordinator,
+ Please Approve Purchase Agreements bellow link
+
+ ${object.basick_information() | safe}
+ ${object.line_information() | safe}
+
+ % set setup_url = object.make_url()
+
+ Approve Purchase Agreements
+
+
+
+ ]]>
+
+
+
+ Purchase Manager
+ ${(object.user_id.email and '%s <%s>' % (object.user_id.company_id.name, object.user_id.email) or '')|safe}
+ Purchase Agreements Approve
+
+
+
+ Dear Managment,
+ Please Approve Purchase Agreements bellow link
+
+ ${object.basick_information() | safe}
+ ${object.line_information() | safe}
+
+
+ % set setup_url = object.make_url()
+
+ Approve Purchase Agreements
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/edi/purchase_mail_template.xml b/MKS_Tradex_Backend_2/edi/purchase_mail_template.xml
new file mode 100755
index 0000000..ed75164
--- /dev/null
+++ b/MKS_Tradex_Backend_2/edi/purchase_mail_template.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+ Purchase Coordinator
+ ${(object.user_id.email and '%s <%s>' % (object.user_id.company_id.name, object.user_id.email) or '')|safe}
+ Purchase Request Approve
+
+
+
+ Dear Coordinator,
+ Please Approve Purchase Request bellow link
+
+
+ % set setup_url = object.make_url()
+
+ Approve Purchase Request
+
+
+
+ ]]>
+
+
+
+ Purchase Manager
+ ${(object.user_id.email and '%s <%s>' % (object.user_id.company_id.name, object.user_id.email) or '')|safe}
+ Purchase Request confirm
+
+
+
+ Dear Manager,
+ Please Confirm Purchase Request bellow link
+
+
+ % set setup_url = object.make_url()
+
+ Approve Purchase Request
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/edi/sale_mail_template.xml b/MKS_Tradex_Backend_2/edi/sale_mail_template.xml
new file mode 100755
index 0000000..2a1795f
--- /dev/null
+++ b/MKS_Tradex_Backend_2/edi/sale_mail_template.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+ Sale Manager
+ ${(object.user_id.email and '%s <%s>' % (object.user_id.company_id.name, object.user_id.email) or '')|safe}
+ Sale Management Approval
+
+
+
+ Dear Sale Management ,
+ Please Approve RFQ Request bellow link
+
+
+ % set setup_url = object.make_url()
+
+ Approve Sale Order Request
+
+
+
+ ]]>
+
+
+
+ Sale Store Keeper
+ Management Approval
+
+
+
+ Dear ${(object.user_id.name)} ,
+ Please Approve RFQ Request bellow link
+
+ % set setup_url = object.make_url()
+
+ Approve Sale Order Request
+
+
+
+ ]]>
+
+
+
+ Sale Logistic Approval
+ ${(object.user_id.email and '%s <%s>' % (object.user_id.company_id.name, object.user_id.email) or '')|safe}
+ Logistic Approval
+
+
+
+ Dear Logistic,
+ Please Approve Sale Order bellow link
+
+ % set setup_url = object.make_url()
+
+ Approve Sale Order Request
+
+
+
+ ]]>
+
+
+
+ Credit controller
+ Credit Controller Confirm Sale Order
+
+
+
+ Dear Credit Controller,
+ Please Approve Sale Order bellow link
+
+ % set setup_url = object.make_url()
+
+ Approve Sale Order Request
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/models/__init__.py b/MKS_Tradex_Backend_2/models/__init__.py
new file mode 100755
index 0000000..46dcdfc
--- /dev/null
+++ b/MKS_Tradex_Backend_2/models/__init__.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import purchase_requisition
+from . import purchase_order
+from . import stock_picking
+from . import sale_order
+from . import account_invoice
diff --git a/MKS_Tradex_Backend_2/models/account_invoice.py b/MKS_Tradex_Backend_2/models/account_invoice.py
new file mode 100755
index 0000000..6d91d75
--- /dev/null
+++ b/MKS_Tradex_Backend_2/models/account_invoice.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, SUPERUSER_ID, _
+
+class account_move(models.Model):
+ _inherit = "account.move"
+
+ state = fields.Selection(selection_add=[('approval','Financial Approval')])
+
+ def make_invoice_url(self):
+ for invoice in self:
+ base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', default='http://localhost:8069')
+ if base_url:
+ base_url += '/web/login?db=%s&login=%s&key=%s#id=%s&model=%s' % (
+ self._cr.dbname, '', '', invoice.id, 'account.move')
+ return base_url
+
+ def get_email(self):
+ group_id = self.env['ir.model.data'].get_object_reference('account', 'group_account_manager')[1]
+ email = ''
+ if group_id:
+ group_id = self.env['res.groups'].browse(group_id)
+ for user in group_id.users:
+ if user.partner_id.email:
+ if email:
+ email = email+','+user.partner_id.email
+ else:
+ email = user.partner_id.email
+ return email
+
+ def send_invoice_approval_mail(self):
+ email = self.get_email()
+ if email:
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'invoice_approval_mail_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.write({'email_to': email})
+ mail_tem.send_mail(self.id,True)
+
+
+ def action_post(self):
+ if self.env.user.has_group('account.group_account_manager'):
+ return super(account_move,self).action_post()
+ else:
+ if self.type in ['out_invoice','out_refund','in_invoice','in_refund'] and self.state == 'draft':
+ self.send_invoice_approval_mail()
+ self.state = 'approval'
+ else:
+ return super(account_move,self).action_post()
+
diff --git a/MKS_Tradex_Backend_2/models/purchase_order.py b/MKS_Tradex_Backend_2/models/purchase_order.py
new file mode 100755
index 0000000..cc369c8
--- /dev/null
+++ b/MKS_Tradex_Backend_2/models/purchase_order.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, SUPERUSER_ID, _
+
+class purchase_order(models.Model):
+ _inherit = "purchase.order"
+
+ state = fields.Selection([
+ ('draft', 'RFQ'),
+ ('sent', 'RFQ Sent'),
+ ('approved', 'RFQ Approved'),
+ ('po_approval', 'PO Approval'),
+ ('to approve', 'To Approve'),
+ ('purchase', 'Purchase Order'),
+ ('done', 'Locked'),
+ ('cancel', 'Cancelled')
+ ], string='Status', readonly=True, index=True, copy=False, default='draft', tracking=True)
+
+ def make_url(self):
+ record_id = self.id
+ menu_id = self.env.ref('purchase.menu_purchase_rfq').id
+ action_id = self.env.ref('purchase.purchase_rfq').id
+ base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
+ if base_url:
+ base_url += \
+ '/web?#id=%s&view_type=form&model=%s&menu_id=%s&action=%s' % (
+ self.id, self._name, menu_id, action_id)
+ return base_url
+
+ def action_manager_approval(self):
+ group_id = self.env['ir.model.data'].get_object_reference('MKS_Tradex_Backend_2', 'group_purchase_coordinator')[1]
+ if group_id:
+ browse_group = self.env['res.groups'].browse(group_id)
+ for user in browse_group.users:
+ manager_mail = user.partner_id.email
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'purchase_req_coordinator_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.send_mail(self.id,True)
+ mail_tem.write({'email_to': manager_mail})
+ self.state = 'approved'
+
+ def button_confirm_mks(self):
+ group_id = self.env['ir.model.data'].get_object_reference('purchase', 'group_purchase_manager')[1]
+ if group_id:
+ browse_group = self.env['res.groups'].browse(group_id)
+ for user in browse_group.users:
+ manager_mail = user.partner_id.email
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'purchase_req_manager_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.send_mail(self.id,True)
+ mail_tem.write({'email_to': manager_mail})
+ self.state = 'po_approval'
+ return True
+
+
+ def button_confirm(self):
+ for order in self:
+ if order.state not in ['draft', 'sent','approved','po_approval']:
+ continue
+ order._add_supplier_to_product()
+ # Deal with double validation process
+ if order.company_id.po_double_validation == 'one_step'\
+ or (order.company_id.po_double_validation == 'two_step'\
+ and order.amount_total < self.env.company.currency_id._convert(
+ order.company_id.po_double_validation_amount, order.currency_id, order.company_id, order.date_order or fields.Date.today()))\
+ or order.user_has_groups('purchase.group_purchase_manager'):
+ order.button_approve()
+ else:
+ order.write({'state': 'to approve'})
+ return True
diff --git a/MKS_Tradex_Backend_2/models/purchase_requisition.py b/MKS_Tradex_Backend_2/models/purchase_requisition.py
new file mode 100755
index 0000000..f5b2250
--- /dev/null
+++ b/MKS_Tradex_Backend_2/models/purchase_requisition.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, SUPERUSER_ID, _
+
+
+PURCHASE_REQUISITION_STATES = [
+ ('draft', 'Draft'),
+ ('approval', 'Approval'),
+ ('manager_approval','Manager Approval'),
+ ('approved','Approved'),
+ ('ongoing', 'Ongoing'),
+ ('in_progress', 'Confirmed'),
+ ('open', 'Bid Selection'),
+ ('done', 'Closed'),
+ ('cancel', 'Cancelled'),
+]
+
+class purchase_requisition(models.Model):
+ _inherit = "purchase.requisition"
+
+ state = fields.Selection(PURCHASE_REQUISITION_STATES,
+ 'Status', tracking=True, required=True,
+ copy=False, default='draft')
+
+ state_blanket_order = fields.Selection(PURCHASE_REQUISITION_STATES, compute='_set_state')
+
+ @api.depends('state')
+ def _set_state(self):
+ self.state_blanket_order = self.state
+
+ def basick_information(self):
+ order_table=''
+ order_table +='''
+
+
+ Purchase Representative
+ Agreement Type
+ Vendor
+ Agreement Deadline
+ Delivery Date
+
+ '''
+ Purchase_rep = self.user_id and self.user_id.name or ' '
+ agreement_type = self.type_id and self.type_id.name or ' '
+ vendor = self.vendor_id and self.vendor_id.name or ' '
+ agreement_deadline = self.date_end or ' '
+ delivery_date = self.schedule_date or ' '
+ order_table += "" + '' + Purchase_rep + ' ' + '' + str(agreement_type) + ' ' + '' + vendor + ' ' + '' + str(agreement_deadline) + ' ' + '' + str(delivery_date) + ' ' + " "
+
+ order_table += '''
+
+ '''
+
+ return order_table
+
+
+ def line_information(self):
+ order_table=''
+ order_table +='''
+
+
+ Product
+ Quantity
+ Order Quantity
+ Scheduled Date
+ Unit Price
+
+ '''
+ for line in self.line_ids:
+ product_name = line.product_id and line.product_id.name or ' '
+ schedule_date = line.schedule_date or ' '
+ order_table += "" + '' + product_name + ' ' + '' + str(line.product_qty) + ' ' + '' + str(line.qty_ordered) + ' ' + '' + str(schedule_date) + ' ' + '' + str(line.price_unit) + ' ' + " "
+ order_table += '''
+
+ '''
+
+ return order_table
+
+
+
+ def make_url(self):
+ record_id = self.id
+ menu_id = self.env.ref('purchase_requisition.menu_purchase_requisition_pro_mgt').id
+ action_id = self.env.ref('purchase_requisition.action_purchase_requisition').id
+ base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
+ if base_url:
+ base_url += \
+ '/web?#id=%s&view_type=form&model=%s&menu_id=%s&action=%s' % (
+ self.id, self._name, menu_id, action_id)
+ return base_url
+
+ def action_approval(self):
+ group_id = self.env['ir.model.data'].get_object_reference('MKS_Tradex_Backend_2', 'group_purchase_coordinator')[1]
+ if group_id:
+ browse_group = self.env['res.groups'].browse(group_id)
+ for user in browse_group.users:
+ coordinator_mail = user.partner_id.email
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'purchase_coordinator_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.send_mail(self.id,True)
+ mail_tem.write({'email_to': coordinator_mail})
+ self.state = 'approval'
+
+ def action_coordinator_approval(self):
+ group_id = self.env['ir.model.data'].get_object_reference('purchase', 'group_purchase_manager')[1]
+ if group_id:
+ browse_group = self.env['res.groups'].browse(group_id)
+ for user in browse_group.users:
+ manager_mail = user.partner_id.email
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'purchase_manager_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.send_mail(self.id,True)
+ mail_tem.write({'email_to': manager_mail})
+ self.state = 'manager_approval'
+
+ def action_manager_approval(self):
+ self.state = 'approved'
+
diff --git a/MKS_Tradex_Backend_2/models/sale_order.py b/MKS_Tradex_Backend_2/models/sale_order.py
new file mode 100755
index 0000000..0c50a66
--- /dev/null
+++ b/MKS_Tradex_Backend_2/models/sale_order.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, SUPERUSER_ID, _
+
+class sale_order(models.Model):
+ _inherit = "sale.order"
+
+ # logistics_id = fields.Many2one('res.users',string="Logistics Users")
+ # credit_controller_id = fields.Many2one('res.users',string="Credit Controller")
+
+ state = fields.Selection([
+ ('draft', 'Quotation'),
+ ('approval', 'RFQ approval'),
+ ('approved', 'RFQ Approved'),
+ ('logistics_approval', 'Logistics Approval'),
+ ('logistics_approved', 'Logistics Approved'),
+ ('credit_approval', 'Credit Approval'),
+ ('sent', 'Quotation Sent'),
+ ('sale', 'Sales Order'),
+ ('done', 'Locked'),
+ ('cancel', 'Cancelled'),
+ ], string='Status', readonly=True, copy=False, index=True, tracking=3, default='draft')
+
+ def make_url(self):
+ record_id = self.id
+ menu_id = self.env.ref('sale.menu_sale_quotations').id
+ action_id = self.env.ref('sale.action_quotations_with_onboarding').id
+ base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
+ if base_url:
+ base_url += \
+ '/web?#id=%s&view_type=form&model=%s&menu_id=%s&action=%s' % (
+ self.id, self._name, menu_id, action_id)
+ return base_url
+
+
+ def action_confirm_approval_request(self):
+ group_id = self.env['ir.model.data'].get_object_reference('sales_team', 'group_sale_manager')[1]
+ if group_id:
+ browse_group = self.env['res.groups'].browse(group_id)
+ for user in browse_group.users:
+ print ("=====",user.name)
+ manager_mail = user.partner_id.email
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'sale_manager_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.write({'email_to': manager_mail})
+ mail_tem.send_mail(self.id,True)
+ self.state = 'approval'
+ return True
+
+ def action_manager_approval(self):
+ user_email = self.user_id.partner_id.email
+ manager = self.env.user.partner_id.email
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'sale_user_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.send_mail(self.id,True)
+ mail_tem.write({'email_from': manager,'email_to': user_email})
+ self.state = 'approved'
+ return True
+
+ def action_logistics_approval(self):
+ group_id = self.env['ir.model.data'].get_object_reference('MKS_Tradex_Backend_2', 'group_sale_logistics')[1]
+ if group_id:
+ browse_group = self.env['res.groups'].browse(group_id)
+ for user in browse_group.users:
+ manager_mail = user.partner_id.email
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'sale_logistic_approval_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.send_mail(self.id,True)
+ mail_tem.write({'email_to': manager_mail})
+ self.state = 'logistics_approval'
+ return True
+
+ def action_logistics_approve(self):
+ group_id = self.env['ir.model.data'].get_object_reference('MKS_Tradex_Backend_2', 'group_credit_controller')[1]
+ if group_id:
+ browse_group = self.env['res.groups'].browse(group_id)
+ for user in browse_group.users:
+ credit_controller = user.partner_id.email
+ user_email = self.user_id.partner_id.email
+ mtp =self.env['mail.template']
+ ir_model_data = self.env['ir.model.data']
+ template_id = ir_model_data.get_object_reference('MKS_Tradex_Backend_2', 'sale_credit_controller_template')
+ mail_tem=mtp.browse(template_id[1])
+ mail_tem.send_mail(self.id,True)
+ mail_tem.write({'email_from': user_email,'email_to': credit_controller})
+ self.state = 'sale'
+ return True
+
+
+ def action_credit_approval(self):
+ self.state = 'credit_approval'
+ return True
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/models/stock_picking.py b/MKS_Tradex_Backend_2/models/stock_picking.py
new file mode 100755
index 0000000..7f886d3
--- /dev/null
+++ b/MKS_Tradex_Backend_2/models/stock_picking.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, SUPERUSER_ID, _
+
+class stock_picking(models.Model):
+ _inherit = "stock.picking"
+
+ state = fields.Selection(selection_add=[('qa_approval', 'QA approval')],
+ )
+
+ def button_validate_qa_approval(self):
+ self.state = 'qa_approval'
+ return True
+
+
diff --git a/MKS_Tradex_Backend_2/security/account_security.xml b/MKS_Tradex_Backend_2/security/account_security.xml
new file mode 100755
index 0000000..c6e3b03
--- /dev/null
+++ b/MKS_Tradex_Backend_2/security/account_security.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Accountant
+
+
+
+ Finance Manager
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/security/purchase_security.xml b/MKS_Tradex_Backend_2/security/purchase_security.xml
new file mode 100644
index 0000000..c771245
--- /dev/null
+++ b/MKS_Tradex_Backend_2/security/purchase_security.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+ Store Keeper
+
+
+
+ Purchase Coordinator
+
+
+
+
+
+ Management
+
+
+
+
+
+
+ Store Keeper
+
+
+
+ Logistics and Warehouse Coordinator
+
+
+
+
+
+ Credit Controller
+
+
+
+
+ Management
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/views/account_move_views.xml b/MKS_Tradex_Backend_2/views/account_move_views.xml
new file mode 100644
index 0000000..20491a6
--- /dev/null
+++ b/MKS_Tradex_Backend_2/views/account_move_views.xml
@@ -0,0 +1,17 @@
+
+
+
+ view.account.move.inherit.form
+ account.move
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/views/purchase_order_views.xml b/MKS_Tradex_Backend_2/views/purchase_order_views.xml
new file mode 100644
index 0000000..299ce53
--- /dev/null
+++ b/MKS_Tradex_Backend_2/views/purchase_order_views.xml
@@ -0,0 +1,39 @@
+
+
+
+ view.purchase.order.inherit.form
+ purchase.order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/views/purchase_requisition_views.xml b/MKS_Tradex_Backend_2/views/purchase_requisition_views.xml
new file mode 100644
index 0000000..4e2e6f4
--- /dev/null
+++ b/MKS_Tradex_Backend_2/views/purchase_requisition_views.xml
@@ -0,0 +1,35 @@
+
+
+
+ view.purchase.requisition.inherit.form
+ purchase.requisition
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/views/sale_order_view.xml b/MKS_Tradex_Backend_2/views/sale_order_view.xml
new file mode 100644
index 0000000..af26804
--- /dev/null
+++ b/MKS_Tradex_Backend_2/views/sale_order_view.xml
@@ -0,0 +1,47 @@
+
+
+
+ mks.sale.order.inherit.form
+ sale.order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MKS_Tradex_Backend_2/views/stock_picking.xml b/MKS_Tradex_Backend_2/views/stock_picking.xml
new file mode 100644
index 0000000..e373903
--- /dev/null
+++ b/MKS_Tradex_Backend_2/views/stock_picking.xml
@@ -0,0 +1,36 @@
+
+
+
+ view.stock.picking.inherit.form
+ stock.picking
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tradex_backend_2/__init__.py b/tradex_backend_2/__init__.py
new file mode 100755
index 0000000..33bbab5
--- /dev/null
+++ b/tradex_backend_2/__init__.py
@@ -0,0 +1,4 @@
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import models
+from . import wizard
diff --git a/tradex_backend_2/__manifest__.py b/tradex_backend_2/__manifest__.py
new file mode 100755
index 0000000..43ec2e4
--- /dev/null
+++ b/tradex_backend_2/__manifest__.py
@@ -0,0 +1,20 @@
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+{
+ 'name': 'Tradex Backend',
+ 'version': '13.0.1.0',
+ 'category': 'Stock',
+ 'description': """
+ This module allows you to add location in stock move
+d
+""",
+ 'depends': ['sale_management','sale_stock'],
+ 'data': [
+ 'security/ir.model.access.csv',
+ 'wizard/stock_location_qty_views.xml',
+ 'wizard/inventory_view_report.xml',
+ 'views/stock_move_views.xml',
+ 'views/sale_order_views.xml',
+ 'views/inventory_view.xml',
+ ],
+
+}
diff --git a/tradex_backend_2/models/__init__.py b/tradex_backend_2/models/__init__.py
new file mode 100755
index 0000000..1331820
--- /dev/null
+++ b/tradex_backend_2/models/__init__.py
@@ -0,0 +1,3 @@
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import stock_move_location_lines
diff --git a/tradex_backend_2/models/stock_move_location_lines.py b/tradex_backend_2/models/stock_move_location_lines.py
new file mode 100755
index 0000000..a75a3a9
--- /dev/null
+++ b/tradex_backend_2/models/stock_move_location_lines.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, SUPERUSER_ID, _
+from odoo.exceptions import ValidationError
+
+class stock_move(models.Model):
+ _inherit = 'stock.move'
+
+ move_location_lines = fields.One2many('stock.move.location.lines','move_id', string='Move Location Lines')
+
+
+ # @api.constrains('move_location_lines','move_location_lines.qty')
+ # def check_location_quantity(self):
+ # for move in self:
+ # if move.move_location_lines:
+ # qty = 0
+ # for line in move.move_location_lines:
+ # qty += line.qty
+ #
+ # if qty > move.product_uom_qty:
+ # raise ValidationError(_("Location Quantity must less or equal %s Quantity")% move.product_uom_qty)
+
+ @api.constrains('move_location_lines','move_location_lines.qty')
+ def check_location_quantity(self):
+ for move in self:
+ if move.move_line_nosuggest_ids:
+ base_qty = 0
+ location_qty = 0
+ for base_move in move.move_line_nosuggest_ids:
+ base_qty += base_move.qty_done
+ for location_move in move.move_location_lines:
+ location_qty += location_move.qty
+ if location_qty > base_qty:
+ raise ValidationError(_("Location Quantity must less or equal %s Quantity") % base_qty)
+ else:
+ raise ValidationError(_("Please add some done quantity in above table"))
+
+class stock_move_location_lines(models.Model):
+ _name = "stock.move.location.lines"
+
+ def get_company_id(self):
+ company_id = False
+ if self.move_id and self.move_id.picking_id:
+ if self.move_id.picking_id and self.move_id.picking_id.location_dest_id:
+ if self.move_id.picking_id.location_dest_id.company_id:
+ company_id = self.move_id.picking_id.location_dest_id.company_id.id
+ return company_id
+
+ product_id = fields.Many2one('product.product', string='Product', required="1")
+ qty = fields.Float(string='Quantity', required="1")
+ uom = fields.Many2one('uom.uom', string='UOM', required="1")
+ location_id = fields.Many2one('stock.location', string='Location', required="1")
+ company_id = fields.Many2one('res.company', string='Owner', default=get_company_id)
+ move_id = fields.Many2one('stock.move', string='Move')
+
+
+
+
diff --git a/tradex_backend_2/security/ir.model.access.csv b/tradex_backend_2/security/ir.model.access.csv
new file mode 100644
index 0000000..d267de4
--- /dev/null
+++ b/tradex_backend_2/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_stock_move_location_lines_all,stock.move.lines.all,model_stock_move_location_lines,,1,1,1,1
diff --git a/tradex_backend_2/views/inventory_view.xml b/tradex_backend_2/views/inventory_view.xml
new file mode 100644
index 0000000..52f201d
--- /dev/null
+++ b/tradex_backend_2/views/inventory_view.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+ form.backend.inventory.view
+ stock.move.location.lines
+
+
+
+
+
+
+
+ tree.backend.inventory.view
+ stock.move.location.lines
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Inventory View - Search
+ stock.move.location.lines
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Inventory View
+ ir.actions.act_window
+ stock.move.location.lines
+ tree,form
+
+
+
+
+
\ No newline at end of file
diff --git a/tradex_backend_2/views/sale_order_views.xml b/tradex_backend_2/views/sale_order_views.xml
new file mode 100755
index 0000000..76a4ef8
--- /dev/null
+++ b/tradex_backend_2/views/sale_order_views.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ view.odoo.sale.order.inherit.form
+ sale.order
+
+
+
+
+
+
+
+
+
+
diff --git a/tradex_backend_2/views/stock_move_views.xml b/tradex_backend_2/views/stock_move_views.xml
new file mode 100755
index 0000000..f3f1a5b
--- /dev/null
+++ b/tradex_backend_2/views/stock_move_views.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ view.stock.move.views.inherit.form
+ stock.move
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ view.stock.move.location.views.inherit.form
+ stock.move
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tradex_backend_2/wizard/__init__.py b/tradex_backend_2/wizard/__init__.py
new file mode 100644
index 0000000..5b8d70b
--- /dev/null
+++ b/tradex_backend_2/wizard/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import stock_location_qty
+from . import inventory_view_report
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/tradex_backend_2/wizard/inventory_view_report.py b/tradex_backend_2/wizard/inventory_view_report.py
new file mode 100644
index 0000000..e5a5be5
--- /dev/null
+++ b/tradex_backend_2/wizard/inventory_view_report.py
@@ -0,0 +1,162 @@
+ # -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
+import itertools
+from operator import itemgetter
+import operator
+# ========For Excel=======
+from io import BytesIO
+import xlwt
+from xlwt import easyxf, Formula
+import base64
+from datetime import datetime
+# =======================
+
+class inventory_view_report(models.TransientModel):
+ _name = "inventory.view.report"
+ _description = 'Inventory View Report'
+
+ product_ids = fields.Many2many('product.product', string='Products')
+ excel_file = fields.Binary('Excel File')
+
+ def create_excel_header(self,worksheet):
+ header_style = easyxf('font:height 300;pattern: pattern solid, fore_color silver_ega; align: horiz center, vert center;font:bold True;')
+ sub_header = easyxf('font:height 210;pattern: pattern solid, fore_color silver_ega;font:bold True;')
+ content = easyxf('font:height 200;')
+ worksheet.write_merge(2, 3, 2, 4, 'Inventory View Report ', header_style)
+ row=5
+
+ return worksheet, row+1
+
+ def create_excel_table_header(self,row,worksheet,company_ids):
+ header_style = easyxf('font:height 150;pattern: pattern solid, fore_color silver_ega; align: horiz center, vert center;font:bold True;' "borders: top thin,bottom thin,right thin, left thin")
+ worksheet.write(row, 0,'ITEM CODE', header_style)
+ worksheet.write(row, 1,'DESCRIPTION', header_style)
+ worksheet.write(row, 2,'TOTAL QUANTITY', header_style)
+ worksheet.write(row, 3,'LOCATION', header_style)
+
+ col=4
+ for company in company_ids:
+ worksheet.write(row, col,company.name, header_style)
+ col+=1
+
+ row+=1
+
+ return worksheet, row
+
+
+
+ def get_company(self):
+ sql_query = """select DISTINCT sl.company_id from stock_move_location_lines as smll LEFT JOIN stock_location as sl ON sl.id = smll.location_id LEFT JOIN res_company as rc ON rc.id=sl.company_id where smll.product_id in %s"""
+ params = (tuple(self.product_ids.ids),)
+ self.env.cr.execute(sql_query, params)
+ results = self.env.cr.dictfetchall()
+ company_ids = [result.get('company_id') for result in results]
+ company_ids = self.env['res.company'].browse(company_ids)
+ return company_ids
+
+ def get_location(self,product_id):
+ sql_query = """select DISTINCT location_id from stock_move_location_lines where product_id = %s"""
+ params = (product_id.id,)
+ self.env.cr.execute(sql_query, params)
+ results = self.env.cr.dictfetchall()
+ location_ids = [result.get('location_id') for result in results]
+ location_ids = self.env['stock.location'].browse(location_ids)
+ return location_ids
+
+
+ def get_quantity(self,product,location,company):
+ sql_query = """select sum(smll.qty) from stock_move_location_lines as smll LEFT JOIN stock_location as sl ON sl.id = smll.location_id LEFT JOIN res_company as rc ON rc.id=sl.company_id where smll.product_id = %s and smll.location_id = %s and sl.company_id = %s"""
+ params = (product.id,location.id,company.id)
+ self.env.cr.execute(sql_query, params)
+ results = self.env.cr.dictfetchall()[0]
+ if results.get('sum'):
+ return results.get('sum')
+ return 0.0
+
+
+ def create_excel_table_values(self,row,worksheet,company_ids):
+ header_style = easyxf('font:height 150;pattern: pattern solid, fore_color silver_ega; align: horiz center, vert center;font:bold True;' "borders: top thin,bottom thin,right thin, left thin")
+ content = easyxf('font:height 200; align: vert center;' "borders: top thin,bottom thin,right thin, left thin",num_format_str='0.00')
+ content_bold = easyxf('font:height 200; align: vert center;font:bold True;' "borders: top thin,bottom thin,right thin, left thin",num_format_str='0.00')
+ for product in self.product_ids:
+ location_ids = self.get_location(product)
+ if location_ids:
+ worksheet.write(row, 0,product.default_code, content)
+ worksheet.write(row, 1,product.name, content)
+ worksheet.write(row, 2,product.qty_available, content)
+ com_sum_row = row
+ row+=1
+ com_sum=[]
+ for company in company_ids:
+ com_sum.append({
+ 'company_id':company.id,
+ 'qty':0.0
+ })
+ for location in location_ids:
+ worksheet.write(row, 3, location.display_name, content)
+ col=4
+ total_qty = 0.0
+ for company_id in company_ids:
+ qty = self.get_quantity(product,location,company_id)
+ total_qty += qty
+ if qty:
+ for com in com_sum:
+ if com.get('company_id') == company_id.id:
+ com.update({
+ 'qty':com.get('qty') + qty
+ })
+
+ worksheet.write(row, col, qty, content)
+ col+=1
+ worksheet.write(row, 2, total_qty, content_bold)
+ row+=1
+ s_c = 3
+ for company in company_ids:
+ s_c += 1
+ for com in com_sum:
+ if company.id == com.get('company_id'):
+ worksheet.write(com_sum_row, s_c, com.get('qty'), content_bold)
+ row+=1
+
+ return worksheet, row
+
+
+ def print_report(self):
+ workbook = xlwt.Workbook()
+ filename = 'Inventory View.xls'
+ worksheet = workbook.add_sheet('Inventory Views')
+ worksheet,row = self.create_excel_header(worksheet)
+ for i in range(0,200):
+ worksheet.col(i).width = 150 * 30
+ if i == 1:
+ worksheet.col(i).width = 230 * 30
+
+ for i in range(5,50):
+ worksheet.row(i).height_mismatch = True
+ worksheet.col(i).width = 130 * 30
+ worksheet.row(i).height = 20 * 20
+
+ company_ids = self.get_company()
+ worksheet,row = self.create_excel_table_header(row,worksheet,company_ids)
+ worksheet,row = self.create_excel_table_values(row,worksheet,company_ids)
+
+# company_ids = self.env['res.company'].browse(company)
+# print ("======",lines,company_ids)
+# def create_excel_table_val(self,worksheet,company):
+ fp = BytesIO()
+ workbook.save(fp)
+ fp.seek(0)
+ excel_file = base64.encodestring(fp.read())
+ fp.close()
+ self.write({'excel_file': excel_file})
+
+ active_id = self.ids[0]
+ return {'type': 'ir.actions.act_url', 'url': 'web/content/?model=inventory.view.report&download=true&field=excel_file&id=%s&filename=%s' % (active_id, filename), 'target': 'new', }
+
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
diff --git a/tradex_backend_2/wizard/inventory_view_report.xml b/tradex_backend_2/wizard/inventory_view_report.xml
new file mode 100644
index 0000000..2c5b242
--- /dev/null
+++ b/tradex_backend_2/wizard/inventory_view_report.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+ view.inventory.view.report.form
+ inventory.view.report
+
+
+
+
+
+
+ Inventory View Report
+ ir.actions.act_window
+ inventory.view.report
+ form
+
+ new
+
+
+
+
+
diff --git a/tradex_backend_2/wizard/stock_location_qty.py b/tradex_backend_2/wizard/stock_location_qty.py
new file mode 100644
index 0000000..4d874d6
--- /dev/null
+++ b/tradex_backend_2/wizard/stock_location_qty.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
+
+class stock_location_quantity(models.TransientModel):
+ _name = "stock.location.quantity"
+ _description = 'location quantity'
+
+ product_id = fields.Many2one('product.product', string='Product')
+ qty = fields.Float('Quantity On Hand')
+ location_lines = fields.One2many('stock.location.quantity.line','slq_id', string='Location Quantity Lines')
+
+ @api.model
+ def default_get(self, fields):
+ res = super(stock_location_quantity,self).default_get(fields)
+ if res.get('product_id'):
+ product_id = self.env['product.product'].browse(res.get('product_id'))
+ res.update({
+ 'qty':product_id.qty_available
+ })
+ line_ids = self.env['stock.move.location.lines'].search([('product_id','=',product_id.id)])
+ vals = []
+ for line in line_ids:
+ vals.append((0,0,{
+ 'location_id':line.location_id and line.location_id.id or False,
+ 'quantity':line.qty or 0.0,
+ 'company_id':line.company_id and line.company_id.id or False,
+ }))
+ res.update({'location_lines':vals})
+ return res
+
+
+class stock_location_quantity_line(models.TransientModel):
+ _name = "stock.location.quantity.line"
+ _description = 'location quantity'
+
+ location_id = fields.Many2one('stock.location', string='Location')
+ quantity = fields.Float('Quantity')
+ slq_id = fields.Many2one('stock.location.quantity', string='Stock Location')
+ company_id = fields.Many2one('res.company', string='Owner')
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
diff --git a/tradex_backend_2/wizard/stock_location_qty_views.xml b/tradex_backend_2/wizard/stock_location_qty_views.xml
new file mode 100644
index 0000000..d58ef0b
--- /dev/null
+++ b/tradex_backend_2/wizard/stock_location_qty_views.xml
@@ -0,0 +1,38 @@
+
+
+
+
+ view.stock.location.quantity.form
+ stock.location.quantity
+
+
+
+
+
+
+ Location Quantity
+ ir.actions.act_window
+ stock.location.quantity
+ form
+
+ new
+
+
+