multi committe
This commit is contained in:
parent
70147afc66
commit
88bd1269eb
|
|
@ -12,11 +12,14 @@
|
|||
"data/sequence.xml",
|
||||
|
||||
"views/annual_request_views.xml",
|
||||
"views/purchase_inherit_views.xml",
|
||||
"views/addendum_views.xml",
|
||||
"views/purchase_requisition.xml",
|
||||
"data/mail_activity.xml",
|
||||
"views/menu.xml",
|
||||
"views/annual_rfq_views.xml",
|
||||
"data/mail_template_annual_rfq.xml",
|
||||
"views/select_reason_rfq_views.xml",
|
||||
"views/report_annual_rfq.xml",
|
||||
"wizard/annual_cancel_wizard_view.xml"
|
||||
],
|
||||
"application": True,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="email_template_annual_rfq" model="mail.template">
|
||||
<field name="name">Purchase Order: Send RFQ</field>
|
||||
<field name="model_id" ref="odex25_annual_purchase.model_annual_rfq"/>
|
||||
<field name="subject">RFQ ${object.name or ''}</field>
|
||||
<field name="body_html" type="html">
|
||||
<div style="margin: 0px; padding: 0px;">
|
||||
<p style="margin: 0px; padding: 0px; font-size: 13px;">
|
||||
Dear ${object.vendor_id.name}
|
||||
% if object.vendor_id.parent_id:
|
||||
(${object.vendor_id.parent_id.name})
|
||||
% endif
|
||||
<br/><br/>
|
||||
Here is in attachment a request for quotation <strong>${object.name}</strong>
|
||||
% if object.partner_ref:
|
||||
with reference: ${object.partner_ref}
|
||||
% endif
|
||||
from ${object.company_id.name}.
|
||||
<br/><br/>
|
||||
If you have any questions, please do not hesitate to contact us.
|
||||
<br/><br/>
|
||||
Best regards,
|
||||
</p>
|
||||
</div></field>
|
||||
<field name="report_template" ref="odex25_annual_purchase.action_report_annual_rfq"/>
|
||||
<field name="report_name">${(object.name or '').replace('/','_')}</field>
|
||||
<field name="lang">${object.vendor_id.lang}</field>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -11,4 +11,13 @@
|
|||
<field name="prefix">AD%(y)s-</field>
|
||||
<field name="padding">4</field>
|
||||
</record>
|
||||
<record id="seq_annual_rfq" model="ir.sequence">
|
||||
<field name="name">Annual RFQ Sequence</field>
|
||||
<field name="code">annual.rfq</field>
|
||||
<field name="prefix">RFQ </field>
|
||||
<field name="padding">5</field>
|
||||
<field name="number_next">1</field>
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -589,6 +589,7 @@ msgid "Please set Selected Vendor."
|
|||
msgstr "يرجى تحديد المورد المختار."
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq_line__product_id
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_addendum_line__product_id
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_request_line__product_id
|
||||
msgid "Product"
|
||||
|
|
@ -638,6 +639,7 @@ msgid "Purpose"
|
|||
msgstr "مبررات طلب الشراء (الغرض)"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq_line__quantity
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_addendum_line__quantity
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_request_line__quantity
|
||||
msgid "Quantity"
|
||||
|
|
@ -688,11 +690,7 @@ msgstr "موصى به من قبل اللجنة"
|
|||
msgid "Reference"
|
||||
msgstr "المرجع"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/purchase_inherit.py:0
|
||||
#, python-format
|
||||
msgid "Refuse Reason"
|
||||
msgstr "سبب الرفض"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_odx_annual_request_form
|
||||
|
|
@ -774,12 +772,6 @@ msgstr "موافقة مدير الخدمات المشتركة؟"
|
|||
msgid "SSD Reject"
|
||||
msgstr "رفض مدير الخدمات المشتركة"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/purchase_inherit.py:0
|
||||
#, python-format
|
||||
msgid "Select Reason"
|
||||
msgstr "اختر السبب"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_request__vendor_id
|
||||
msgid "Selected Vendor"
|
||||
|
|
@ -813,19 +805,6 @@ msgstr "مدير الخدمات المشتركة"
|
|||
msgid "Sorry, No Committee members"
|
||||
msgstr "عفواً، لا يوجد أعضاء في اللجنة"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/purchase_inherit.py:0
|
||||
#, python-format
|
||||
msgid "Sorry, the minimum number of committee votes is not satisfied"
|
||||
msgstr "عفواً، لم يتم استيفاء الحد الأدنى من أصوات اللجنة"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/purchase_inherit.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Sorry, you cannot sign this quotation. You need more committee members to "
|
||||
"choose it"
|
||||
msgstr "عفواً، لا يمكنك توقيع عرض السعر هذا. أنت بحاجة إلى المزيد من أعضاء اللجنة لاختياره"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_request__date_start
|
||||
|
|
@ -875,6 +854,7 @@ msgid "Type of the exception activity on record."
|
|||
msgstr "نوع النشاط الاستثنائي في السجل."
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq_line__price_unit
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_addendum_line__price_unit
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_request_line__price_unit
|
||||
msgid "Unit Price"
|
||||
|
|
@ -892,17 +872,15 @@ msgstr "رسائل غير مقروءة"
|
|||
msgid "Unread Messages Counter"
|
||||
msgstr "عداد الرسائل غير المقروءة"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq_line__uom_id
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_addendum_line__uom_id
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_request_line__uom_id
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_purchase_order_form_annual_rfq_odx
|
||||
msgid "UoM"
|
||||
msgstr "وحدة القياس"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_addendum__vendor_id
|
||||
msgid "Vendor"
|
||||
msgstr "المورد"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields.selection,name:odex25_annual_purchase.selection__odx_annual_request__state__to_manager
|
||||
|
|
@ -948,15 +926,6 @@ msgstr ""
|
|||
msgid "اسم القسم"
|
||||
msgstr ""
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/purchase_inherit.py:0
|
||||
#: code:addons/odex25_annual_purchase/models/purchase_inherit.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/purchase_inherit.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/purchase_inherit.py:0
|
||||
#, python-format
|
||||
msgid "تم رفض عرض السعر من قبل جميع أعضاء اللجنة."
|
||||
msgstr ""
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_purchase_order_form_annual_rfq_odx
|
||||
msgid "عناصر الطلب"
|
||||
|
|
@ -1006,10 +975,13 @@ msgstr "الملاحظة"
|
|||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/annual_request.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/annual_request.py:0
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__attach_no
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_request__attach_no
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_odx_annual_request_form
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_po_form_products_for_annual_committee
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_po_form_products_for_tech_committee
|
||||
#, python-format
|
||||
msgid "Documents"
|
||||
msgstr "المرفقات"
|
||||
|
||||
|
|
@ -1040,9 +1012,8 @@ msgstr "رفض"
|
|||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq_line__description
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_request_line__description
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_po_form_products_for_annual_committee
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_po_form_products_for_tech_committee
|
||||
msgid "Technical Description"
|
||||
msgstr "المواصفات الفنية"
|
||||
|
||||
|
|
@ -1057,8 +1028,199 @@ msgstr "هل أنت متأكد أنك تريد المتابعة؟"
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: model:ir.model,name:odex25_annual_purchase.model_annual_rfq
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
#, python-format
|
||||
msgid "Request for Quotation"
|
||||
msgstr "طلب عرض سعر"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__recommendation_order
|
||||
msgid "Recommend"
|
||||
msgstr "موصى به"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__partner_id
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__vendor_id
|
||||
msgid "Vendor"
|
||||
msgstr "المورد"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__partner_ref
|
||||
msgid "Partner Ref"
|
||||
msgstr "رقم إشارة المورد"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__source_request_ref
|
||||
msgid "Source Request Reference"
|
||||
msgstr "المستند المصدر"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__no_of_approve
|
||||
msgid "No. of Votes "
|
||||
msgstr "عدد الاختيارات"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__user_id
|
||||
msgid "Purchase Representative"
|
||||
msgstr "مندوب الشراء"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq_line__subtotal
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_addendum_line__price_subtotal
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
msgid "Subtotal"
|
||||
msgstr "الإجمالي الفرعي"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__amount_tax
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq_line__taxes_id
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_odx_annual_addendum_line__taxes_id
|
||||
msgid "Taxes"
|
||||
msgstr "الضرائب"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields.selection,name:odex25_annual_purchase.selection__odx_annual_request__committee_status__recommended
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_po_form_products_for_annual_committee
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
msgid "Recommended"
|
||||
msgstr "موصى به"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields.selection,name:odex25_annual_purchase.selection__annual_rfq__state__draft
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
msgid "Sign"
|
||||
msgstr "تنفيذ عرض سعر"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields.selection,name:odex25_annual_purchase.selection__annual_rfq__state__sent
|
||||
msgid "Sent to Vendor"
|
||||
msgstr "تم إرسال طلب عرض سعر"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields.selection,name:odex25_annual_purchase.selection__annual_rfq__state__committee
|
||||
msgid "Committees"
|
||||
msgstr "اللجنة"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields.selection,name:odex25_annual_purchase.selection__annual_rfq__state__po
|
||||
msgid "Purchase Order"
|
||||
msgstr "أمر شراء"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Sorry You cannot sign this quotation ,YOU NEED MORE COMMITTE MEMBERS TO "
|
||||
"choose it"
|
||||
msgstr "عذرًا، لا يمكنك اعتماد هذا العرض، تحتاج إلى عدد أكبر من أعضاء اللجنة لاختياره."
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#, python-format
|
||||
msgid "Cannot continue: the source document is Approval stage."
|
||||
msgstr "لا يمكن المتابعة: المستند المصدر في مرحلة الاعتماد."
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#, python-format
|
||||
msgid "You have already refused this RFQ before."
|
||||
msgstr "لقد قمت برفض هذا العرض مسبقًا."
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#, python-format
|
||||
msgid "You have already selected this RFQ before."
|
||||
msgstr "لقد قمت باختيار هذا العرض مسبقًا."
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_select_reason_rfq_form
|
||||
msgid "Provide Recommendation"
|
||||
msgstr "تقديم التوصية"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_refuse_reason_rfq_form
|
||||
msgid "Provide Refuse Reason"
|
||||
msgstr "تقديم سبب الرفض"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_select_reason_rfq__select_reason
|
||||
#, python-format
|
||||
msgid "Select Reason"
|
||||
msgstr "سبب الاختيار"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/committe.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/committe.py:0
|
||||
#, python-format
|
||||
msgid "Recommended by %s: %s"
|
||||
msgstr "تمت التوصية من قبل %s: %s"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: code:addons/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: code:addons/odoo/STANDARD_MODULES/test/odex25_purchase/odex25_purchase/odex25_annual_purchase/models/annual_rfq.py:0
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_refuse_reason_rfq__refuse_reason
|
||||
#, python-format
|
||||
msgid "Refuse Reason"
|
||||
msgstr "سبب الرفض"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
msgid "Send by Email"
|
||||
msgstr "إرسال بالبريد الإلكتروني"
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
msgid "Select"
|
||||
msgstr "اختيار"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
msgid "Refuse"
|
||||
msgstr "رفض"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__amount_untaxed
|
||||
msgid "Untaxed Amount"
|
||||
msgstr "المبلغ قبل الضريبة"
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model:ir.model.fields,field_description:odex25_annual_purchase.field_annual_rfq__amount_total
|
||||
msgid "Total"
|
||||
msgstr "الإجمالي"
|
||||
|
||||
|
||||
|
||||
#. module: odex25_annual_purchase
|
||||
#: model_terms:ir.ui.view,arch_db:odex25_annual_purchase.view_annual_rfq_form
|
||||
msgid "Committe Members"
|
||||
msgstr "أعضاء اللجنة"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from . import annual_request
|
||||
from . import purchase_inherit
|
||||
from . import addendum
|
||||
from . import purchase_requisition
|
||||
from . import annual_rfq
|
||||
from . import committe
|
||||
|
|
|
|||
|
|
@ -56,8 +56,6 @@ class AnnualPurchaseRequest(models.Model):
|
|||
ssd_approve = fields.Boolean(string="SSD Approve", default=False)
|
||||
seo_approve = fields.Boolean(string="SEO Approve", default=False)
|
||||
|
||||
rfq_count = fields.Integer(string='RFQs/POs', compute='_compute_counts')
|
||||
po_count = fields.Integer(string='PO Count', compute='_compute_counts')
|
||||
|
||||
can_create_agreement = fields.Boolean(compute='_compute_can_create_agreement')
|
||||
|
||||
|
|
@ -79,6 +77,64 @@ class AnnualPurchaseRequest(models.Model):
|
|||
readonly=True,
|
||||
)
|
||||
addendum_count = fields.Integer(string='Addendums', compute='_compute_addendum_count', readonly=True)
|
||||
|
||||
rfq_ids = fields.One2many('annual.rfq', 'source_request_ref', string="RFQs")
|
||||
rfq_count = fields.Integer(compute='_compute_rfq_count', string='RFQs')
|
||||
|
||||
def _compute_rfq_count(self):
|
||||
for rec in self:
|
||||
rec.rfq_count = len(rec.rfq_ids)
|
||||
|
||||
def action_create_rfq(self):
|
||||
"""Create an RFQ (annual.rfq) from this annual request and copy its lines."""
|
||||
for rec in self:
|
||||
|
||||
rfq_vals = {
|
||||
'source_request_ref': rec.id,
|
||||
'vendor_id': rec.vendor_id.id,
|
||||
'request_date': fields.Date.context_today(self),
|
||||
'purpose': rec.purpose or rec.description or '',
|
||||
'note': rec.note or '',
|
||||
'company_id': rec.env.company.id,
|
||||
'currency_id': rec.currency_id.id,
|
||||
}
|
||||
|
||||
line_commands = []
|
||||
for l in rec.line_ids:
|
||||
line_commands.append((0, 0, {
|
||||
'product_id': l.product_id.id,
|
||||
'description': l.description or l.technical_spec or l.product_id.display_name,
|
||||
'quantity': l.quantity or 1.0,
|
||||
'uom_id': (l.uom_id and l.uom_id.id) or l.product_id.uom_po_id.id,
|
||||
'price_unit': l.price_unit or 0.0,
|
||||
# taxes تُحدّد لاحقًا من المستخدم (إن رغبت أضف من تصنيف المنتج)
|
||||
}))
|
||||
rfq_vals['line_ids'] = line_commands
|
||||
|
||||
rfq = self.env['annual.rfq'].create(rfq_vals)
|
||||
|
||||
return {
|
||||
'name': _('RFQ'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'annual.rfq',
|
||||
'view_mode': 'form',
|
||||
'res_id': rfq.id,
|
||||
'target': 'current',
|
||||
}
|
||||
def action_open_rfqs(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': _('RFQs'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'annual.rfq',
|
||||
'view_mode': 'tree,form',
|
||||
'domain': [('source_request_ref', '=', self.id)],
|
||||
'context': {'default_source_request_ref': self.id,
|
||||
'default_vendor_id': self.vendor_id.id or False},
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
|
||||
def _compute_addendum_count(self):
|
||||
Addendum = self.env['odx.annual.addendum']
|
||||
for rec in self:
|
||||
|
|
@ -116,25 +172,17 @@ class AnnualPurchaseRequest(models.Model):
|
|||
('res_id', '=', rec.id)
|
||||
])
|
||||
|
||||
purchase_orders = self.env['purchase.order'].search([('annual_request_id', '=', rec.id)])
|
||||
count_po = 0
|
||||
if purchase_orders:
|
||||
count_po = Attachment.search_count([
|
||||
('res_model', '=', 'purchase.order'),
|
||||
('res_id', 'in', purchase_orders.ids)
|
||||
])
|
||||
|
||||
rec.attach_no = count_self + count_po
|
||||
|
||||
rec.attach_no = count_self
|
||||
|
||||
def get_attachments(self):
|
||||
self.ensure_one()
|
||||
Attachment = self.env['ir.attachment']
|
||||
|
||||
purchase_orders = self.env['purchase.order'].search([('annual_request_id', '=', self.id)])
|
||||
|
||||
domain = ['|',
|
||||
'&', ('res_model', '=', self._name), ('res_id', 'in', self.ids),
|
||||
'&', ('res_model', '=', 'purchase.order'), ('res_id', 'in', purchase_orders.ids)
|
||||
'&', ('res_model', '=', self._name), ('res_id', 'in', self.ids)
|
||||
]
|
||||
|
||||
return {
|
||||
|
|
@ -224,91 +272,9 @@ class AnnualPurchaseRequest(models.Model):
|
|||
for rec in self:
|
||||
rec.can_create_agreement = rec.state in ('ceo','approved') and not rec.agreement_id and bool(rec.vendor_id)
|
||||
|
||||
@api.depends('agreement_id')
|
||||
def _compute_counts(self):
|
||||
PO = self.env['purchase.order']
|
||||
for rec in self:
|
||||
rec.rfq_count = PO.search_count([('annual_request_id','=',rec.id)])
|
||||
if rec.agreement_id:
|
||||
rec.po_count = PO.search_count([('requisition_id','=',rec.agreement_id.id)])
|
||||
else:
|
||||
rec.po_count = 0
|
||||
|
||||
def action_open_rfqs(self):
|
||||
self.ensure_one()
|
||||
|
||||
domain = [('annual_request_id', '=', self.id)]
|
||||
rfqs = self.env['purchase.order'].search(domain)
|
||||
|
||||
if len(rfqs) == 1:
|
||||
return {
|
||||
'name': _('RFQ'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'purchase.order',
|
||||
'view_mode': 'form',
|
||||
'res_id': rfqs.id,
|
||||
'target': 'current',
|
||||
'context': {'default_annual_request_id': self.id, 'default_origin': self.name},
|
||||
}
|
||||
|
||||
return {
|
||||
'name': _('RFQs / Purchase Orders'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'purchase.order',
|
||||
'views': [(False, 'tree'), (False, 'form')],
|
||||
'domain': domain,
|
||||
'context': {'default_annual_request_id': self.id, 'default_origin': self.name},
|
||||
}
|
||||
|
||||
def action_create_rfq(self):
|
||||
self.ensure_one()
|
||||
self._check_lines()
|
||||
order_line_vals = []
|
||||
for line in self.line_ids:
|
||||
line.sudo()
|
||||
order_line_vals.append((0, 0, {
|
||||
'product_id': line.product_id.id,
|
||||
'name': line.description or line.product_id.description_purchase or line.product_id.name,
|
||||
'product_qty': line.quantity,
|
||||
'product_uom': line.uom_id.id,
|
||||
'price_unit': line.price_unit or 0.0,
|
||||
'date_planned': fields.Datetime.now(),
|
||||
'account_analytic_id': self.department_id and self.department_id.analytic_account_id and self.department_id.analytic_account_id.id or False,
|
||||
'taxes_id': [(6, 0, line.product_id.supplier_taxes_id.ids)],
|
||||
}))
|
||||
|
||||
# PO = self.env['purchase.order'].sudo().create({
|
||||
# 'origin': self.name,
|
||||
# 'annual_request_id': self.id,
|
||||
# 'department_id': self.department_id.id if hasattr(self.department_id, 'id') else False,
|
||||
# 'purpose': self.purpose,
|
||||
# 'is_recommended': False,
|
||||
# 'allow_empty_vendor': True,
|
||||
# 'order_line': order_line_vals,
|
||||
# 'purchase_commitee': self.committee_enabled,
|
||||
# })
|
||||
#
|
||||
# if self.committee_enabled:
|
||||
# PO._copy_committee_from_annual_request()
|
||||
|
||||
return {
|
||||
'name': _("Annual RFQ"),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'purchase.order',
|
||||
'view_mode': 'form',
|
||||
'target': 'current',
|
||||
'context': {
|
||||
'default_origin': self.name,
|
||||
'default_annual_request_id': self.id,
|
||||
'default_department_id': self.department_id.id if self.department_id else False,
|
||||
'default_purpose': self.purpose,
|
||||
'default_is_recommended': False,
|
||||
|
||||
'default_partner_id': False,
|
||||
|
||||
'default_order_line': order_line_vals,
|
||||
},
|
||||
}
|
||||
|
||||
def action_open_agreement(self):
|
||||
self.ensure_one()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,359 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError,ValidationError
|
||||
|
||||
class PurchaseRFQ(models.Model):
|
||||
_name = 'annual.rfq'
|
||||
_description = 'Request for Quotation'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
|
||||
name = fields.Char(string='Reference Number', default='New', copy=False, tracking=True)
|
||||
source_request_ref = fields.Many2one( 'odx.annual.request', string='Source Request Reference', help='Original request number/reference (optional)')
|
||||
user_id = fields.Many2one(
|
||||
'res.users', string='Purchase Representative', index=True, tracking=True,
|
||||
default=lambda self: self.env.user, check_company=True)
|
||||
vendor_id = fields.Many2one(
|
||||
'res.partner',
|
||||
string='Vendor',
|
||||
domain=[('supplier_rank', '>', 0)],
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
'res.partner',
|
||||
string='Vendor',
|
||||
|
||||
)
|
||||
request_date = fields.Date(string='Request Date', default=fields.Date.context_today, tracking=True)
|
||||
partner_ref = fields.Char(string='Partner Ref')
|
||||
note = fields.Text(string='Notes')
|
||||
state = fields.Selection([
|
||||
('draft', 'Sign'),
|
||||
('sent', 'Sent to Vendor'),
|
||||
('committee', 'Committees'),
|
||||
('po', 'Purchase Order'),
|
||||
('approved', 'Approved'),
|
||||
('rejected', 'Rejected'),
|
||||
], string='Status', default='draft', tracking=True)
|
||||
purpose = fields.Text(string='Purpose')
|
||||
company_id = fields.Many2one('res.company', default=lambda self: self.env.company, required=True)
|
||||
currency_id = fields.Many2one('res.currency', string='Currency',
|
||||
default=lambda self: self.env.company.currency_id.id)
|
||||
|
||||
notes = fields.Text('Terms and Conditions')
|
||||
line_ids = fields.One2many('annual.rfq.line', 'rfq_id', string='RFQ Lines')
|
||||
|
||||
amount_untaxed = fields.Monetary(string='Untaxed Amount', compute='_compute_amounts',
|
||||
currency_field='currency_id', store=True)
|
||||
amount_tax = fields.Monetary(string='Taxes', compute='_compute_amounts',
|
||||
currency_field='currency_id', store=True)
|
||||
amount_total = fields.Monetary(string='Total', compute='_compute_amounts',
|
||||
currency_field='currency_id', store=True)
|
||||
|
||||
attach_no = fields.Integer(string='Documents', compute='_compute_attach_no')
|
||||
|
||||
committe_members = fields.One2many('committe.member', 'rfq_id', string='Committee Members (RFQ)')
|
||||
|
||||
recommendation_order = fields.Boolean(string='Recommend')
|
||||
purchase_commitee = fields.Boolean(
|
||||
string='Purchase Committee?',
|
||||
related='source_request_ref.committee_enabled',
|
||||
store=False,
|
||||
readonly=True
|
||||
)
|
||||
source_request_state = fields.Selection(
|
||||
related='source_request_ref.state',
|
||||
string='Source Request State',
|
||||
store=False, readonly=True
|
||||
)
|
||||
show_committee_actions = fields.Boolean(
|
||||
compute='_compute_show_committee_actions',
|
||||
store=False
|
||||
)
|
||||
no_of_approve = fields.Integer("No. of Votes ", compute="_compute_no_approve")
|
||||
technical_attachment_ids = fields.Many2many(
|
||||
'ir.attachment',
|
||||
string="Technical Attachments",
|
||||
help="Upload technical offer documents here"
|
||||
)
|
||||
@api.depends('committe_members')
|
||||
def _compute_no_approve(self):
|
||||
for rec in self:
|
||||
rec.no_of_approve = len(rec.committe_members)
|
||||
|
||||
|
||||
def _compute_show_committee_actions(self):
|
||||
for rec in self:
|
||||
rec.show_committee_actions = bool(
|
||||
rec.source_request_ref
|
||||
and rec.source_request_state == 'committee'
|
||||
and rec.purchase_commitee
|
||||
and rec.state in ('committee', 'draft', 'sent')
|
||||
)
|
||||
|
||||
def _get_current_member_vote(self):
|
||||
self.ensure_one()
|
||||
return self.env['committe.member'].search([
|
||||
('rfq_id', '=', self.id),
|
||||
('user_id', '=', self.env.user.id),
|
||||
], limit=1)
|
||||
def action_recommend(self):
|
||||
for order in self:
|
||||
order.recommendation_order = True
|
||||
|
||||
|
||||
def action_select_rfq(self):
|
||||
self.ensure_one()
|
||||
member = self._get_current_member_vote()
|
||||
if member:
|
||||
if member.select:
|
||||
raise UserError(_("You have already selected this RFQ before."))
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Select Reason'),
|
||||
'res_model': 'select.reason.rfq',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_rfq_id': self.id
|
||||
}
|
||||
}
|
||||
|
||||
def action_refuse_rfq(self):
|
||||
self.ensure_one()
|
||||
member = self._get_current_member_vote()
|
||||
if member and member.refused:
|
||||
raise UserError(_("You have already refused this RFQ before."))
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Refuse Reason'),
|
||||
'res_model': 'refuse.reason.rfq',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_rfq_id': self.id
|
||||
}
|
||||
}
|
||||
|
||||
def action_submit_to_committees(self):
|
||||
res = super(PurchaseRFQ, self).action_submit_to_committees()
|
||||
for rec in self:
|
||||
for user in rec.source_request_ref.committe_members:
|
||||
existing = self.env['committe.member'].search([
|
||||
('rfq_id', '=', rec.id),
|
||||
('user_id', '=', user.id),
|
||||
], limit=1)
|
||||
if not existing:
|
||||
self.env['committe.member'].create({
|
||||
'rfq_id': rec.id,
|
||||
'user_id': user.id,
|
||||
})
|
||||
return res
|
||||
def _compute_attach_no(self):
|
||||
for rec in self:
|
||||
rec.attach_no = self.env['ir.attachment'].search_count([
|
||||
('res_model', '=', 'annual.rfq'),
|
||||
('res_id', '=', rec.id)
|
||||
])
|
||||
|
||||
def get_attachments(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': 'Attachments',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'ir.attachment',
|
||||
'view_mode': 'kanban,tree,form',
|
||||
'domain': [('res_model', '=', 'annual.rfq'), ('res_id', '=', self.id)],
|
||||
'context': {'default_res_model': 'annual.rfq', 'default_res_id': self.id},
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def action_rfq_send(self):
|
||||
self.ensure_one()
|
||||
if not self.vendor_id:
|
||||
raise UserError(_('Please select a Vendor before sending the Request for Quotation.'))
|
||||
|
||||
self.partner_id = self.vendor_id.id
|
||||
|
||||
try:
|
||||
template = self.env.ref('odex25_annual_purchase.email_template_annual_rfq')
|
||||
except ValueError:
|
||||
template = False
|
||||
|
||||
try:
|
||||
compose_form = self.env.ref('mail.email_compose_message_wizard_form')
|
||||
except ValueError:
|
||||
compose_form = False
|
||||
|
||||
ctx = dict(self.env.context or {})
|
||||
ctx.update({
|
||||
'default_model': 'annual.rfq',
|
||||
'active_model': 'annual.rfq',
|
||||
'active_id': self.id,
|
||||
'default_res_id': self.id,
|
||||
'default_use_template': bool(template),
|
||||
'default_template_id': template.id if template else False,
|
||||
'default_composition_mode': 'mass_mail',
|
||||
'force_email': True,
|
||||
'mail_post_autofollow': False,
|
||||
'mail_post_autolog': False,
|
||||
'default_notify': False,
|
||||
'default_is_log': False,
|
||||
})
|
||||
|
||||
lang = self.env.context.get('lang')
|
||||
if template and template.lang:
|
||||
lang_map = template._render_lang([self.id])
|
||||
lang = lang_map.get(self.id, lang)
|
||||
self = self.with_context(lang=lang)
|
||||
|
||||
ctx['model_description'] = _('Request for Quotation')
|
||||
|
||||
self.state ='sent'
|
||||
return {
|
||||
'name': _('Compose Email'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'mail.compose.message',
|
||||
'views': [(compose_form.id, 'form')],
|
||||
'view_id': compose_form.id,
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
def action_mark_sent(self):
|
||||
self.write({'state': 'sent'})
|
||||
|
||||
def _validate_lines_simple(self):
|
||||
self.ensure_one()
|
||||
|
||||
if not self.line_ids:
|
||||
raise UserError(_('الرجاء إضافة سطر واحد على الأقل.'))
|
||||
|
||||
if any((l.quantity or 0.0) <= 0.0 for l in self.line_ids):
|
||||
raise UserError(_('ضروري الكمية تكون أكبر من 0.'))
|
||||
|
||||
if any((l.price_unit or 0.0) <= 0.0 for l in self.line_ids):
|
||||
raise UserError(_('رجاء أضِف الأسعار لكل السطور.'))
|
||||
|
||||
def _sync_approved_prices_to_request(self):
|
||||
|
||||
self.ensure_one()
|
||||
req = self.source_request_ref
|
||||
if not req or not req.line_ids:
|
||||
return
|
||||
|
||||
rfq_by_product = {}
|
||||
for l in self.line_ids:
|
||||
rfq_by_product.setdefault(l.product_id.id, []).append(l)
|
||||
|
||||
def _convert_price(p):
|
||||
if self.currency_id and req.currency_id and self.currency_id != req.currency_id:
|
||||
return self.currency_id._convert(
|
||||
p or 0.0,
|
||||
req.currency_id,
|
||||
self.company_id,
|
||||
fields.Date.context_today(self)
|
||||
)
|
||||
return p or 0.0
|
||||
|
||||
for rline in req.line_ids.sorted(key=lambda x: x.id):
|
||||
if not rline.product_id:
|
||||
continue
|
||||
bucket = rfq_by_product.get(rline.product_id.id)
|
||||
if bucket:
|
||||
rfq_line = bucket.pop(0)
|
||||
new_price = _convert_price(rfq_line.price_unit)
|
||||
vals = {
|
||||
'price_unit': new_price,
|
||||
|
||||
}
|
||||
rline.write(vals)
|
||||
def action_sign_rfq(self):
|
||||
for rec in self:
|
||||
rec._validate_lines_simple()
|
||||
if self.source_request_ref.committee_enabled and self.no_of_approve < self.source_request_ref.min_approve:
|
||||
raise ValidationError(
|
||||
_("Sorry You cannot sign this quotation ,YOU NEED MORE COMMITTE MEMBERS TO choose it"))
|
||||
|
||||
if rec.source_request_ref.state in ['committee', 'procurement']:
|
||||
rec._sync_approved_prices_to_request()
|
||||
rec.state = 'po'
|
||||
if rec.source_request_ref.ssd_approve:
|
||||
rec.source_request_ref.state = 'ssd'
|
||||
elif rec.source_request_ref.seo_approve:
|
||||
rec.source_request_ref.state = 'ceo'
|
||||
else:
|
||||
rec.source_request_ref.state = 'purchase'
|
||||
else:
|
||||
raise UserError(_(
|
||||
'Cannot continue: the source document is Approval stage.'
|
||||
))
|
||||
|
||||
|
||||
|
||||
|
||||
@api.depends('line_ids.subtotal', 'line_ids.tax_amount')
|
||||
def _compute_amounts(self):
|
||||
for rec in self:
|
||||
untaxed = sum(rec.line_ids.mapped('subtotal'))
|
||||
tax_amt = sum(rec.line_ids.mapped('tax_amount'))
|
||||
rec.amount_untaxed = untaxed
|
||||
rec.amount_tax = tax_amt
|
||||
rec.amount_total = untaxed + tax_amt
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('name', 'New') in (False, '/', 'New'):
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('annual.rfq') or 'New'
|
||||
return super().create(vals)
|
||||
|
||||
|
||||
def action_approve(self):
|
||||
for rec in self:
|
||||
rec.state = 'approved'
|
||||
|
||||
def action_reject(self):
|
||||
for rec in self:
|
||||
rec.state = 'rejected'
|
||||
|
||||
|
||||
class PurchaseRFQLine(models.Model):
|
||||
_name = 'annual.rfq.line'
|
||||
_description = 'RFQ Line Items'
|
||||
_order = 'sequence, id'
|
||||
|
||||
rfq_id = fields.Many2one('annual.rfq', string='RFQ', required=True, ondelete='cascade')
|
||||
sequence = fields.Integer(default=10)
|
||||
product_id = fields.Many2one('product.product', string="Product", required=True)
|
||||
description = fields.Char(string="Technical Description")
|
||||
quantity = fields.Float(string="Quantity", default=1.0)
|
||||
uom_id = fields.Many2one('uom.uom', string="UoM", related='product_id.uom_po_id')
|
||||
company_id = fields.Many2one(related='rfq_id.company_id', store=True, readonly=True)
|
||||
currency_id = fields.Many2one(related='rfq_id.currency_id', store=True, readonly=True)
|
||||
|
||||
price_unit = fields.Monetary(string="Unit Price", currency_field='currency_id')
|
||||
|
||||
taxes_id = fields.Many2many('account.tax', string='Taxes',
|
||||
domain=['|', ('active', '=', False), ('active', '=', True)])
|
||||
|
||||
# computed totals
|
||||
subtotal = fields.Monetary(string='Subtotal', compute='_compute_amounts',
|
||||
store=True, currency_field='currency_id')
|
||||
tax_amount = fields.Monetary(string='Tax Amount', compute='_compute_amounts',
|
||||
store=True, currency_field='currency_id')
|
||||
|
||||
@api.depends('quantity', 'price_unit', 'taxes_id', 'currency_id')
|
||||
def _compute_amounts(self):
|
||||
for line in self:
|
||||
qty = line.quantity or 0.0
|
||||
price = line.price_unit or 0.0
|
||||
if line.taxes_id:
|
||||
res = line.taxes_id.with_context(force_price_include=False).compute_all(
|
||||
price, currency=line.currency_id, quantity=qty,
|
||||
product=line.product_id, partner=line.rfq_id.vendor_id)
|
||||
line.subtotal = res['total_excluded']
|
||||
line.tax_amount = res['total_included'] - res['total_excluded']
|
||||
else:
|
||||
line.subtotal = qty * price
|
||||
line.tax_amount = 0.0
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
# odx_rfq_committee/models/committee_member_inherit.py
|
||||
from odoo import models, fields, _, api
|
||||
|
||||
class CommitteMembers(models.Model):
|
||||
_inherit = "committe.member"
|
||||
|
||||
rfq_id = fields.Many2one('annual.rfq', string="RFQ")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class SelectReasonRFQ(models.TransientModel):
|
||||
_name = "select.reason.rfq"
|
||||
_description = "RFQ Committee Select Reason"
|
||||
|
||||
select_reason = fields.Text("Select Reason", required=True)
|
||||
rfq_id = fields.Many2one('annual.rfq', string="RFQ", required=True)
|
||||
|
||||
def action_select(self):
|
||||
self.ensure_one()
|
||||
rfq = self.rfq_id
|
||||
|
||||
member = self.env['committe.member'].search([
|
||||
('rfq_id', '=', rfq.id),
|
||||
('user_id', '=', self.env.user.id),
|
||||
], limit=1)
|
||||
|
||||
vals = {
|
||||
'selection_reason': self.select_reason,
|
||||
'select': True,
|
||||
'refused': False,
|
||||
'refusing_reason': False,
|
||||
'user_id': self.env.user.id,
|
||||
'rfq_id': rfq.id,
|
||||
}
|
||||
|
||||
if member:
|
||||
member.write(vals)
|
||||
else:
|
||||
self.env['committe.member'].create(vals)
|
||||
|
||||
if rfq.source_request_ref and hasattr(rfq.source_request_ref, 'actual_vote'):
|
||||
rfq.source_request_ref.actual_vote += 1
|
||||
|
||||
rfq.message_post(body=_("Recommended by %s: %s") % (self.env.user.name, self.select_reason))
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class RefuseReasonRFQ(models.TransientModel):
|
||||
_name = "refuse.reason.rfq"
|
||||
_description = "RFQ Committee Refuse Reason"
|
||||
|
||||
refuse_reason = fields.Text("Refuse Reason", required=True)
|
||||
rfq_id = fields.Many2one('annual.rfq', string="RFQ", required=True)
|
||||
|
||||
def action_refuse(self):
|
||||
self.ensure_one()
|
||||
rfq = self.rfq_id
|
||||
|
||||
member = self.env['committe.member'].search([
|
||||
('rfq_id', '=', rfq.id),
|
||||
('user_id', '=', self.env.user.id),
|
||||
], limit=1)
|
||||
|
||||
vals = {
|
||||
'refusing_reason': self.refuse_reason,
|
||||
'refused': True,
|
||||
'select': False,
|
||||
'selection_reason': False,
|
||||
'user_id': self.env.user.id,
|
||||
'rfq_id': rfq.id,
|
||||
}
|
||||
|
||||
if member:
|
||||
member.write(vals)
|
||||
else:
|
||||
self.env['committe.member'].create(vals)
|
||||
|
||||
if rfq.source_request_ref and hasattr(rfq.source_request_ref, 'actual_vote'):
|
||||
rfq.source_request_ref.actual_vote += 1
|
||||
|
||||
rfq.message_post(body=_("تم الرفض من %s: %s") % (self.env.user.name, self.refuse_reason))
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
|
@ -1,324 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields ,api,_
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_inherit = 'purchase.order'
|
||||
|
||||
annual_request_id = fields.Many2one('odx.annual.request', string="Annual Request", index=True, ondelete='set null')
|
||||
department_id = fields.Many2one('hr.department', string="Department")
|
||||
purpose = fields.Char(string="Purpose")
|
||||
is_recommended = fields.Boolean(string="Recommended by Committee")
|
||||
technical_attachment_id = fields.Many2one(
|
||||
'ir.attachment',
|
||||
string="Technical Offer Attachment",
|
||||
)
|
||||
# حقول محسوبة من الاحتياج السنوي
|
||||
# annual_purchase_commitee = fields.Boolean(
|
||||
# string='Annual Committee?',
|
||||
# compute='_compute_annual_committee_fields',
|
||||
# store=True
|
||||
# )
|
||||
annual_can_committee_vote = fields.Boolean(
|
||||
compute='_compute_annual_can_committee_vote'
|
||||
)
|
||||
is_technical_committee = fields.Boolean(
|
||||
compute='_compute_is_technical_committee',
|
||||
string='Is Technical Committee',
|
||||
store=False
|
||||
)
|
||||
show_send_purchase_manager = fields.Boolean(compute='_compute_show_send_purchase_manager')
|
||||
|
||||
cancel_reason = fields.Text(string="Cancel Reason")
|
||||
@api.depends('state', 'requisition_state', 'requisition_type_exclusive','requisition_id', 'is_purchase_budget')
|
||||
def _compute_show_send_purchase_manager(self):
|
||||
for record in self:
|
||||
if (
|
||||
(record.state == 'sent' and not record.is_purchase_budget and not record.requisition_id)
|
||||
or
|
||||
(record.state == 'wait' and not record.is_purchase_budget and not record.requisition_id)
|
||||
):
|
||||
record.show_send_purchase_manager = False # يظهر الزر
|
||||
else:
|
||||
record.show_send_purchase_manager = True # يخفي الزر
|
||||
|
||||
@api.depends(
|
||||
'requisition_id', 'requisition_id.state', 'requisition_id.purchase_commitee',
|
||||
'annual_request_id', 'annual_request_id.state', 'annual_request_id.committee_enabled'
|
||||
)
|
||||
def _compute_parent_state(self):
|
||||
"""
|
||||
|
||||
"""
|
||||
for rec in self:
|
||||
state = False
|
||||
comm = False
|
||||
|
||||
if rec.requisition_id:
|
||||
state = rec.requisition_id.state or False
|
||||
comm = bool(getattr(rec.requisition_id, 'purchase_commitee', False))
|
||||
elif rec.annual_request_id:
|
||||
state = rec.annual_request_id.state or False
|
||||
comm = bool(getattr(rec.annual_request_id, 'committee_enabled', False))
|
||||
|
||||
rec.parent_state = state
|
||||
rec.purchase_commitee = comm
|
||||
|
||||
def _compute_is_technical_committee(self):
|
||||
for record in self:
|
||||
record.is_technical_committee = self.env.user.has_group(
|
||||
'odex25_annual_purchase.group_technical_committee'
|
||||
)
|
||||
|
||||
|
||||
def _compute_annual_can_committee_vote(self):
|
||||
user = self.env.user
|
||||
for po in self:
|
||||
annual_req = po.annual_request_id
|
||||
if annual_req and annual_req.committee_enabled:
|
||||
is_member = user in annual_req.committe_members
|
||||
po.annual_can_committee_vote = annual_req.sent_to_commitee and is_member
|
||||
else:
|
||||
po.annual_can_committee_vote = False
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
res = super(PurchaseOrder, self).create(vals)
|
||||
if res.annual_request_id and res.annual_request_id.committee_enabled:
|
||||
res._copy_committee_from_annual_request()
|
||||
return res
|
||||
|
||||
def _copy_committee_from_annual_request(self):
|
||||
self.ensure_one()
|
||||
if not self.annual_request_id:
|
||||
return
|
||||
|
||||
annual = self.annual_request_id
|
||||
if not annual.committee_enabled:
|
||||
return
|
||||
|
||||
self.committe_members.unlink()
|
||||
|
||||
for member in annual.committe_members:
|
||||
self.env['committe.member'].create({
|
||||
'po_id': self.id,
|
||||
'user_id': member.id,
|
||||
'select': False,
|
||||
'refused': False,
|
||||
})
|
||||
|
||||
|
||||
@api.constrains('recommendation_order')
|
||||
def check_recommendation_order(self):
|
||||
for rec in self:
|
||||
if not rec.recommendation_order:
|
||||
continue
|
||||
|
||||
domain = [
|
||||
('id', '!=', rec.id),
|
||||
('state', '!=', 'cancel'),
|
||||
('recommendation_order', '=', True),
|
||||
]
|
||||
|
||||
if rec.requisition_id:
|
||||
domain.append(('requisition_id', '=', rec.requisition_id.id))
|
||||
elif rec.annual_request_id:
|
||||
domain.append(('annual_request_id', '=', rec.annual_request_id.id))
|
||||
else:
|
||||
continue
|
||||
if self.env['purchase.order'].search_count(domain):
|
||||
raise ValidationError(_("Only one recommended order is allowed per parent document."))
|
||||
|
||||
@api.depends('state', 'requisition_state', 'requisition_type_exclusive', 'requisition_id', 'is_purchase_budget', 'annual_request_id')
|
||||
def _compute_hide_action_budget_button(self):
|
||||
for record in self:
|
||||
# Domain 1 logic
|
||||
domain1_met = (record.state != 'sign') or \
|
||||
(record.state == 'sign' and
|
||||
record.requisition_state == 'purchase_manager' and
|
||||
record.requisition_type_exclusive == 'exclusive')
|
||||
|
||||
# Domain 2 logic
|
||||
domain2_met = (record.has_requisition) or \
|
||||
(record.state not in ('wait', 'sent')) or \
|
||||
(not record.is_purchase_budget)
|
||||
|
||||
# Combined logic
|
||||
if (domain1_met and record.has_requisition) or (domain2_met and record.state != 'sign'):
|
||||
record.hide_action_budget_button = True
|
||||
else:
|
||||
record.hide_action_budget_button = False
|
||||
|
||||
if record.state == 'wait' and record.annual_request_id:
|
||||
record.hide_action_budget_button = True
|
||||
|
||||
|
||||
def action_select(self):
|
||||
if self.annual_request_id and self.annual_request_id.committee_enabled:
|
||||
self.annual_request_id.actual_vote += 1
|
||||
elif self.requisition_id:
|
||||
self.requisition_id.actual_vote += 1
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Select Reason'),
|
||||
'res_model': 'select.reason',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {'default_order_id': self.id}
|
||||
}
|
||||
|
||||
|
||||
def action_refuse(self):
|
||||
if self.annual_request_id and self.annual_request_id.committee_enabled:
|
||||
self.annual_request_id.actual_vote += 1
|
||||
elif self.requisition_id:
|
||||
self.requisition_id.actual_vote += 1
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Refuse Reason'),
|
||||
'res_model': 'refuse.reason',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {'default_order_id': self.id}
|
||||
}
|
||||
|
||||
def _fill_annual_prices_from_po(self):
|
||||
|
||||
for po in self:
|
||||
annual = po.annual_request_id
|
||||
if not annual:
|
||||
continue
|
||||
|
||||
for rline in annual.line_ids:
|
||||
pol = po.order_line.filtered(lambda l: l.product_id == rline.product_id)[:1]
|
||||
if not pol:
|
||||
continue
|
||||
|
||||
price = pol.price_unit
|
||||
|
||||
if po.currency_id != annual.currency_id:
|
||||
convert_date = po.date_order.date() if po.date_order else fields.Date.context_today(self)
|
||||
price = po.currency_id._convert(
|
||||
price, annual.currency_id, po.company_id, convert_date
|
||||
)
|
||||
|
||||
if pol.product_uom and rline.uom_id and pol.product_uom != rline.uom_id:
|
||||
price = pol.product_uom._compute_price(price, rline.uom_id)
|
||||
|
||||
rline.price_unit = price
|
||||
|
||||
def action_sign(self):
|
||||
if self.annual_request_id and self.annual_request_id.committee_enabled:
|
||||
annual = self.annual_request_id
|
||||
if annual.actual_vote < annual.min_vote:
|
||||
raise ValidationError(_("Sorry, the minimum number of committee votes is not satisfied"))
|
||||
if self.no_of_approve < annual.min_approve:
|
||||
raise ValidationError(
|
||||
_("Sorry, you cannot sign this quotation. You need more committee members to choose it"))
|
||||
|
||||
if self.annual_request_id:
|
||||
other_orders = self.env['purchase.order'].search([
|
||||
('annual_request_id', '=', self.annual_request_id.id),
|
||||
('id', '!=', self.id)
|
||||
])
|
||||
for order in other_orders:
|
||||
order.action_unsign()
|
||||
self.annual_request_id.vendor_id = self.partner_id.id
|
||||
self._fill_annual_prices_from_po()
|
||||
if self.annual_request_id.ssd_approve:
|
||||
self.annual_request_id.state = 'ssd'
|
||||
elif self.annual_request_id.seo_approve:
|
||||
self.annual_request_id.state = 'seo'
|
||||
else:
|
||||
self.annual_request_id.state = 'purchase'
|
||||
|
||||
super(PurchaseOrder, self).action_sign()
|
||||
|
||||
|
||||
def _compute_can_committee_vote(self):
|
||||
user = self.env.user
|
||||
context = self._context or {}
|
||||
from_committee = context.get('from_committee_action', False)
|
||||
|
||||
for po in self:
|
||||
requisition = po.requisition_id
|
||||
annual_request = po.annual_request_id
|
||||
is_member = requisition and user in requisition.committe_members
|
||||
po.can_committee_vote = (requisition.sent_to_commitee or annual_request.sent_to_commitee )
|
||||
|
||||
# bool(
|
||||
# from_committee and
|
||||
# requisition and
|
||||
# requisition.purchase_commitee and
|
||||
# is_member
|
||||
# )
|
||||
|
||||
def _check_requisition_rejection(self):
|
||||
if self.requisition_id:
|
||||
PO = self.env['purchase.order'].search([
|
||||
('requisition_id', '=', self.requisition_id.id)
|
||||
])
|
||||
if PO and all(p.state == 'rejected_by_committee' for p in PO):
|
||||
self.sudo().requisition_id.state = 'rejected_by_committee'
|
||||
self.sudo().requisition_id.sent_to_commitee = False
|
||||
|
||||
elif self.annual_request_id:
|
||||
PO = self.env['purchase.order'].search([
|
||||
('annual_request_id', '=', self.annual_request_id.id)
|
||||
])
|
||||
if PO and all(p.state == 'rejected_by_committee' for p in PO):
|
||||
self.sudo().annual_request_id.state = 'rejected_by_committee'
|
||||
self.sudo().annual_request_id.sent_to_commitee = False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def rejection_committee_head(self):
|
||||
self.sudo().state = 'rejected_by_committee'
|
||||
self._check_requisition_rejection()
|
||||
|
||||
def _check_committee_rejection(self):
|
||||
"""
|
||||
This method checks two conditions:
|
||||
1. If the committee members in the Purchase Requisition are the same as in the Purchase Order.
|
||||
2. If all members in the Purchase Order have refused.
|
||||
If both are true, it changes the PO state.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
if not (self.requisition_id or self.annual_request_id):
|
||||
return
|
||||
|
||||
requisition_users = self.requisition_id.committe_members
|
||||
annual_request_users = self.annual_request_id.committe_members
|
||||
po_users = self.committe_members.mapped('user_id')
|
||||
if self.requisition_id.committe_members:
|
||||
if set(requisition_users.ids) == set(po_users.ids):
|
||||
|
||||
if self.committe_members and all(member.refused for member in self.committe_members):
|
||||
self.write({
|
||||
'state': 'rejected_by_committee',
|
||||
|
||||
})
|
||||
self._check_requisition_rejection()
|
||||
|
||||
self.message_post(body=_("تم رفض عرض السعر من قبل جميع أعضاء اللجنة."))
|
||||
elif self.annual_request_id.committe_members:
|
||||
if set(annual_request_users.ids) == set(po_users.ids):
|
||||
|
||||
if self.committe_members and all(member.refused for member in self.committe_members):
|
||||
self.write({
|
||||
'state': 'rejected_by_committee',
|
||||
|
||||
})
|
||||
self._check_requisition_rejection()
|
||||
|
||||
self.message_post(body=_("تم رفض عرض السعر من قبل جميع أعضاء اللجنة."))
|
||||
|
||||
|
||||
|
||||
return True
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_request_staff,access_request_staff,model_odx_annual_request,purchase.group_purchase_user,1,1,1,0
|
||||
access_request_manager,access_request_manager,model_odx_annual_request,purchase.group_purchase_manager,1,1,1,1
|
||||
access_request_manager,access_request_manager,model_odx_annual_request,purchase.group_purchase_manager,1,1,1,0
|
||||
access_request_committee,access_request_committee,model_odx_annual_request,purchase_requisition_custom.committe_member,1,0,0,0
|
||||
access_request_ssd,access_request_ssd,model_odx_annual_request,hr_base.group_services_manager,1,1,0,0
|
||||
access_request_gm,access_request_gm,model_odx_annual_request,hr_base.group_general_manager,1,1,0,0
|
||||
|
|
@ -8,10 +8,31 @@ access_request_line_staff,access_request_line_staff,model_odx_annual_request_lin
|
|||
access_addendum_staff,access_addendum_staff,model_odx_annual_addendum,purchase.group_purchase_user,1,1,1,0
|
||||
access_addendum_line_staff,access_addendum_line_staff,model_odx_annual_addendum_line,purchase.group_purchase_user,1,1,1,0
|
||||
access_odx_annual_request_reason_wizard_user,odx_annual_request_reason_wizard_user,model_odx_annual_request_reason_wizard,base.group_user,1,1,1,1
|
||||
access_purchase_order_group_technical_committee,purchase_order_group_technical_committee,model_purchase_order,odex25_annual_purchase.group_technical_committee,1,1,0,0
|
||||
access_purchase_order_group_annual_committee,purchase_order_group_annual_committee,model_purchase_order,odex25_annual_purchase.group_annual_committee,1,1,0,0
|
||||
access_annual_request_group_technical_committee,annual_request_group_technical_committee,model_odx_annual_request,odex25_annual_purchase.group_technical_committee,1,1,0,0
|
||||
access_annual_request_group_annual_committee,annual_request_group_annual_committee,model_odx_annual_request,odex25_annual_purchase.group_annual_committee,1,1,0,0
|
||||
|
||||
access_annual_request_line_group_technical_committee,annual_request_line_group_technical_committee,model_odx_annual_request_line,odex25_annual_purchase.group_technical_committee,1,1,0,0
|
||||
access_annual_request_line_group_annual_committee,annual_request_line_group_annual_committee,model_odx_annual_request_line,odex25_annual_purchase.group_annual_committee,1,1,0,0
|
||||
access_annual_request_line_group_annual_committee,annual_request_line_group_annual_committee,model_odx_annual_request_line,odex25_annual_purchase.group_annual_committee,1,1,0,0
|
||||
|
||||
|
||||
|
||||
access_annual_rfq_purchase_user,access_annual_rfq_purchase_user,model_annual_rfq,purchase.group_purchase_user,1,1,1,0
|
||||
access_annual_rfq_purchase_manager,access_annual_rfq_purchase_manager,model_annual_rfq,purchase.group_purchase_manager,1,1,1,0
|
||||
access_annual_rfq_services_manager,access_annual_rfq_services_manager,model_annual_rfq,hr_base.group_services_manager,1,1,1,0
|
||||
access_annual_rfq_general_manager,access_annual_rfq_general_manager,model_annual_rfq,hr_base.group_general_manager,1,1,1,0
|
||||
access_annual_rfq_technical_committee,access_annual_rfq_technical_committee,model_annual_rfq,odex25_annual_purchase.group_technical_committee,1,1,0,0
|
||||
access_annual_rfq_annual_committee,access_annual_rfq_annual_committee,model_annual_rfq,odex25_annual_purchase.group_annual_committee,1,1,0,0
|
||||
|
||||
access_annual_rfq_line_purchase_user,access_annual_rfq_line_purchase_user,model_annual_rfq_line,purchase.group_purchase_user,1,1,1,0
|
||||
access_annual_rfq_line_purchase_manager,access_annual_rfq_line_purchase_manager,model_annual_rfq_line,purchase.group_purchase_manager,1,1,1,0
|
||||
access_annual_rfq_line_services_manager,access_annual_rfq_line_services_manager,model_annual_rfq_line,hr_base.group_services_manager,1,1,1,0
|
||||
access_annual_rfq_line_general_manager,access_annual_rfq_line_general_manager,model_annual_rfq_line,hr_base.group_general_manager,1,1,1,0
|
||||
access_annual_rfq_line_technical_committee,access_annual_rfq_line_technical_committee,model_annual_rfq_line,odex25_annual_purchase.group_technical_committee,1,1,0,0
|
||||
access_annual_rfq_line_annual_committee,access_annual_rfq_line_annual_committee,model_annual_rfq_line,odex25_annual_purchase.group_annual_committee,1,1,0,0
|
||||
|
||||
access_select_reason_rfq_user,access.select.reason.rfq.user,model_select_reason_rfq,base.group_user,1,1,1,1
|
||||
access_refuse_reason_rfq_user,access.refuse.reason.rfq.user,model_refuse_reason_rfq,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
access_select_reason_rfq,access_select_reason_rfq,model_select_reason_rfq,base.group_user,1,1,1,1
|
||||
access_refuse_reason_rfq,access_refuse_reason_rfq,model_refuse_reason_rfq,base.group_user,1,1,1,1
|
||||
|
|
|
@ -19,4 +19,31 @@
|
|||
<field name="name">To Draft</field>
|
||||
<field name="category_id" ref="module_category_purchase_management"/>
|
||||
</record>
|
||||
|
||||
<record id="rule_annual_request_committee_visibility" model="ir.rule">
|
||||
<field name="name">Committee members: see their Annual Requests</field>
|
||||
<field name="model_id" ref="odex25_annual_purchase.model_odx_annual_request"/>
|
||||
<field name="groups" eval="[(4, ref('odex25_annual_purchase.group_annual_committee')),
|
||||
(4, ref('odex25_annual_purchase.group_technical_committee'))]"/>
|
||||
<field name="domain_force">
|
||||
['|',
|
||||
('committe_members', 'in', user.id),
|
||||
('committe_head', '=', user.id)
|
||||
]
|
||||
</field>
|
||||
</record>
|
||||
<record id="rule_rfq_committee_visibility" model="ir.rule">
|
||||
<field name="name">Committee members: see their RFQs</field>
|
||||
<field name="model_id" ref="odex25_annual_purchase.model_annual_rfq"/>
|
||||
<field name="groups" eval="[(4, ref('odex25_annual_purchase.group_annual_committee')),
|
||||
(4, ref('odex25_annual_purchase.group_technical_committee'))]"/>
|
||||
|
||||
<field name="domain_force">
|
||||
['|',
|
||||
('committe_members.user_id', '=', user.id),
|
||||
('source_request_ref.committe_members', 'in', user.id)
|
||||
]
|
||||
</field>
|
||||
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -159,6 +159,6 @@
|
|||
<field name="view_mode">search,tree,form</field>
|
||||
<field name="domain">[('state' , '=' , 'committee')]</field>
|
||||
<field name="context">{'create':False,'edit':False, 'delete': False, 'duplicate':False, 'from_committee_action': True}</field>
|
||||
<field name="groups_id" eval="[(4, ref('purchase_requisition_custom.committe_member')), (4, ref('odex25_annual_purchase.group_technical_committee'))]"/>
|
||||
<field name="groups_id" eval="[(4, ref('odex25_annual_purchase.group_annual_committee')), (4, ref('odex25_annual_purchase.group_technical_committee'))]"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
<!-- views/annual_rfq_views.xml -->
|
||||
<odoo>
|
||||
<!-- شجرة البنود (للـ one2many) -->
|
||||
|
||||
|
||||
<!-- فورم الطلب -->
|
||||
<record id="view_annual_rfq_form" model="ir.ui.view">
|
||||
<field name="name">annual.rfq.form</field>
|
||||
<field name="model">annual.rfq</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Request for Quotation" create="1" edit="1">
|
||||
<header>
|
||||
|
||||
<button name="action_rfq_send"
|
||||
type="object"
|
||||
string="Send by Email"
|
||||
class="btn-primary"
|
||||
groups="purchase.group_purchase_manager, purchase.group_purchase_user"
|
||||
attrs="{'invisible': [('state', '!=', 'draft')]}"
|
||||
/>
|
||||
<button name="action_sign_rfq"
|
||||
type="object"
|
||||
string="Sign"
|
||||
groups="purchase.group_purchase_manager, purchase.group_purchase_user"
|
||||
class="btn-primary"
|
||||
attrs="{'invisible': [('state', 'not in', ['sent','draft'])]}"
|
||||
/>
|
||||
|
||||
<button name="action_select_rfq"
|
||||
type="object"
|
||||
string="Select"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('show_committee_actions','=',False)]}"
|
||||
|
||||
|
||||
/>
|
||||
<button name="action_refuse_rfq"
|
||||
type="object"
|
||||
string="Refuse"
|
||||
attrs="{'invisible': [('show_committee_actions','=',False)]}"
|
||||
|
||||
|
||||
/>
|
||||
<button type="object" name="action_recommend"
|
||||
groups="purchase_requisition_custom.group_select_recommended_offer"
|
||||
confirm="Are you sure you want to process ?"
|
||||
attrs="{'invisible':['|',
|
||||
('recommendation_order','=', True),('purchase_commitee', '=', False)]}" string="Recommended"/>
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="draft,sent,committee,po"/>
|
||||
</header>
|
||||
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="get_attachments"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-file-text-o">
|
||||
<field name="attach_no" widget="statinfo" string="Documents"/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<span class="o_form_label" >Request for Quotation</span>
|
||||
<h1>
|
||||
<!-- <field name="priority" widget="priority" class="mr-3"/>-->
|
||||
<field name="name" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<group>
|
||||
<group>
|
||||
|
||||
<field name="show_committee_actions" invisible="1"/>
|
||||
<field name="recommendation_order"/>
|
||||
<field name="purchase_commitee" invisible="1"/>
|
||||
<field name="vendor_id"/>
|
||||
<field name="partner_ref"/>
|
||||
<field name="source_request_ref"/>
|
||||
<field name="no_of_approve"/>
|
||||
</group>
|
||||
<group invisible="1" >
|
||||
<field name="currency_id"/>
|
||||
<field name="company_id" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<notebook>
|
||||
<page string="المنتجات" id="page_product">
|
||||
<field name="line_ids" context="{'default_currency_id': currency_id, 'default_company_id': company_id}">
|
||||
<tree editable="bottom" string="RFQ Lines">
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="sequence" invisible="1"/>
|
||||
<field name="product_id"/>
|
||||
<field name="description"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id" readonly="1"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use','=','purchase'), ('company_id', '=', parent.company_id)]" context="{'default_type_tax_use': 'purchase', 'search_view_ref': 'account.account_tax_view_search'}" options="{'no_create': True}" optional="show"/>
|
||||
<field name="subtotal" sum="Subtotal"/>
|
||||
</tree>
|
||||
</field>
|
||||
<group class="oe_subtotal_footer oe_right">
|
||||
<field name="amount_untaxed" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||
<field name="amount_tax" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||
<div class="oe_subtotal_footer_separator oe_inline">
|
||||
<label for="amount_total"/>
|
||||
</div>
|
||||
<field name="amount_total" nolabel="1" class="oe_subtotal_footer_separator" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||
</group>
|
||||
<field name="notes" class="oe_inline" placeholder="Define your terms and conditions ..."/>
|
||||
<div class="oe_clear"/>
|
||||
</page>
|
||||
<page id="page_committee_members" string="Committe Members"
|
||||
groups="odex25_annual_purchase.group_technical_committee,odex25_annual_purchase.group_annual_committee"
|
||||
>
|
||||
<field name="committe_members">
|
||||
<tree>
|
||||
<field name="user_id"/>
|
||||
<field name="selection_reason"/>
|
||||
<field name="select"/>
|
||||
<field name="refused"/>
|
||||
<field name="refusing_reason"/>
|
||||
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="معلومات أخرى">
|
||||
<group>
|
||||
<field name="user_id"/>
|
||||
</group>
|
||||
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_annual_rfq_form_hide_chatter_for_committee" model="ir.ui.view">
|
||||
<field name="name">annual.rfq.form.hide.chatter.committee</field>
|
||||
<field name="model">annual.rfq</field>
|
||||
<field name="inherit_id" ref="odex25_annual_purchase.view_annual_rfq_form"/>
|
||||
<field name="groups_id" eval="[(6, 0, [ref('odex25_annual_purchase.group_technical_committee')])]"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@id='page_product']" position="replace">
|
||||
<page string="المنتجات" id="page_product">
|
||||
<field name="line_ids" context="{'default_currency_id': currency_id, 'default_company_id': company_id}">
|
||||
<tree editable="bottom" string="RFQ Lines">
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="sequence" invisible="1"/>
|
||||
<field name="product_id"/>
|
||||
<field name="description"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id" readonly="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
<field name="notes" class="oe_inline" placeholder="Define your terms and conditions ..."/>
|
||||
<div class="oe_clear"/>
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="العرض الفني" id="page_technical_offer">
|
||||
<group>
|
||||
<field name="technical_attachment_ids" widget="many2many_binary"
|
||||
string="Technical Attachments"
|
||||
help="Upload technical offer documents here"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//div[@class='oe_chatter']" position="replace"/>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_annual_rfq_tree" model="ir.ui.view">
|
||||
<field name="name">annual.rfq.tree</field>
|
||||
<field name="model">annual.rfq</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Annual RFQs" default_order="id desc">
|
||||
<field name="name"/>
|
||||
<field name="vendor_id"/>
|
||||
<field name="request_date"/>
|
||||
<field name="amount_total"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<record id="action_annual_rfq" model="ir.actions.act_window">
|
||||
<field name="name">Annual RFQs</field>
|
||||
<field name="res_model">annual.rfq</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{}</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
<odoo>
|
||||
<record id="purchase.menu_procurement_management" model="ir.ui.menu">
|
||||
<field name="groups_id" eval="[(4, ref('odex25_annual_purchase.group_technical_committee')),
|
||||
(4, ref('odex25_annual_purchase.group_annual_committee')),
|
||||
(4, ref('purchase.group_purchase_user')),
|
||||
(4, ref('purchase.group_purchase_manager'))]"/>
|
||||
</record>
|
||||
<menuitem id="menu_odx_root" name="Annual Purchase" sequence="10" parent="purchase.menu_purchase_root"/>
|
||||
<menuitem id="menu_odx_requests" name="Annual Requests" parent="menu_odx_root" sequence="10" action="action_odx_annual_request" groups="hr_base.group_general_manager,hr_base.group_services_manager,purchase.group_purchase_user,purchase.group_purchase_manager,odex25_annual_purchase.group_annual_committee,odex25_annual_purchase.group_technical_committee,"/>
|
||||
<menuitem id="menu_odx_annual_committee" name="Annual Committee" parent="menu_odx_root" sequence="11" action="action_annual_committe" groups="purchase_requisition_custom.committe_member,odex25_annual_purchase.group_technical_committee"/>
|
||||
<menuitem id="menu_odx_requests" name="Annual Requests" parent="menu_odx_root" sequence="10" action="action_odx_annual_request" groups="hr_base.group_general_manager,hr_base.group_services_manager,purchase.group_purchase_user,purchase.group_purchase_manager"/>
|
||||
<menuitem id="menu_odx_annual_committee" name="Annual Committee" parent="menu_odx_root" sequence="11" action="action_annual_committe" groups="odex25_annual_purchase.group_annual_committee,odex25_annual_purchase.group_technical_committee"/>
|
||||
<!-- <menuitem id="menu_odx_addendum" name="Addendum" parent="menu_odx_root" sequence="30" action="action_odx_annual_addendum"/>-->
|
||||
</odoo>
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
<odoo>
|
||||
<record id="view_po_form_products_for_tech_committee" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form.products.tech_committee</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase_requisition_custom.purchase_order_custom_form_view"/>
|
||||
<field name="groups_id" eval="[(4, ref('odex25_annual_purchase.group_technical_committee'))]"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form" position="replace">
|
||||
<form>
|
||||
<header>
|
||||
<field name="can_committee_vote" invisible="1"/>
|
||||
<field name="purchase_commitee" invisible="1"/>
|
||||
<field name="requisition_id" invisible="1"/>
|
||||
<button type="object" name="action_select" groups="odex25_annual_purchase.group_technical_committee"
|
||||
attrs="{'invisible':['|', ('state','in',['done','purchase','waiting','cancel']),('can_committee_vote', '=', False)]}"
|
||||
string="Select"/>
|
||||
|
||||
<button type="object" name="action_refuse" groups="odex25_annual_purchase.group_technical_committee"
|
||||
attrs="{'invisible':['|',('state','in',['done','purchase','waiting','cancel']),('can_committee_vote', '=', False)]}"
|
||||
string="Refuse"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,sent,purchase" readonly="1"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="get_attachments" type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-file-text-o">
|
||||
<field name="attach_no" widget="statinfo" string="Documents"/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<span class="o_form_label" attrs="{'invisible': [('state','not in',('draft','sent'))]}">Request for Quotation </span>
|
||||
<span class="o_form_label" attrs="{'invisible': [('state','in',('draft','sent'))]}">Purchase Order </span>
|
||||
<h1>
|
||||
<field name="priority" widget="priority" class="mr-3"/>
|
||||
<field name="name" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<field name="recommendation_order" readonly="1" attrs="{
|
||||
'invisible': [('purchase_commitee', '=', False)]}"/>
|
||||
<field name="partner_id" />
|
||||
<field name="partner_ref" />
|
||||
<field name="annual_request_id" readonly="1"/>
|
||||
<field name="no_of_approve"/>
|
||||
</group>
|
||||
|
||||
<notebook>
|
||||
<page string="Products" name="products">
|
||||
<field name="order_line"
|
||||
widget="section_and_note_one2many"
|
||||
mode="tree"
|
||||
context="{'default_state': 'draft'}"
|
||||
attrs="{'readonly': [('state','in',('done','cancel'))]}">
|
||||
<tree string="عناصر الطلب (لجنة تقنية)" editable="bottom">
|
||||
<field name="display_type" invisible="1"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="product_type" invisible="1"/>
|
||||
<field name="sequence" widget="handle"/>
|
||||
|
||||
<field name="product_id"
|
||||
attrs="{
|
||||
'readonly': [('state','in',('purchase','to approve','done','cancel'))],
|
||||
'required': [('display_type','=',False)]
|
||||
}"
|
||||
context="{'partner_id':parent.partner_id, 'quantity':product_qty,'uom':product_uom, 'company_id': parent.company_id}"
|
||||
force_save="1"
|
||||
domain="[('purchase_ok','=',True),'|',('company_id','=',False),('company_id','=',parent.company_id)]"/>
|
||||
|
||||
<field name="name" widget="section_and_note_text" string="Technical Description"/>
|
||||
|
||||
<field name="product_qty"
|
||||
attrs="{'readonly':[('state','in',('purchase','done','cancel'))]}"/>
|
||||
|
||||
<field name="product_uom"
|
||||
string="UoM"
|
||||
groups="uom.group_uom"
|
||||
attrs="{
|
||||
'readonly':[('state','in',('purchase','done','cancel'))],
|
||||
'required':[('display_type','=',False)]
|
||||
}"
|
||||
force_save="1"/>
|
||||
<field name="product_uom_category_id" invisible="1"/>
|
||||
</tree>
|
||||
|
||||
<form string="عنصر طلب الشراء">
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="display_type" invisible="1"/>
|
||||
|
||||
<group attrs="{'invisible':[('display_type','!=',False)]}">
|
||||
<group>
|
||||
<field name="product_uom_category_id" invisible="1"/>
|
||||
<field name="product_id"
|
||||
context="{'partner_id': parent.partner_id}"
|
||||
widget="many2one_barcode"
|
||||
domain="[('purchase_ok','=',True),'|',('company_id','=',False),('company_id','=',parent.company_id)]"/>
|
||||
<label for="product_qty"/>
|
||||
<div class="o_row">
|
||||
<field name="product_qty"/>
|
||||
<field name="product_uom" groups="uom.group_uom"
|
||||
attrs="{'required':[('display_type','=',False)]}"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
|
||||
<label for="name" string="اسم القسم"
|
||||
attrs="{'invisible':[('display_type','!=','line_section')]}"/>
|
||||
<label for="name" string="ملاحظة"
|
||||
attrs="{'invisible':[('display_type','!=','line_note')]}"/>
|
||||
<field name="name" nolabel="1"
|
||||
attrs="{'invisible':[('display_type','=',False)]}"/>
|
||||
</form>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
<page id="page_committee_members" string="Committee Members"
|
||||
groups="odex25_annual_purchase.group_technical_committee"
|
||||
attrs="{'invisible':['&',('requisition_id','=',False),('annual_request_id','=',False)]}">
|
||||
<field name="committe_members">
|
||||
<tree>
|
||||
<field name="user_id"/>
|
||||
<field name="selection_reason"/>
|
||||
<field name="select"/>
|
||||
<field name="refused"/>
|
||||
<field name="refusing_reason"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
<page string="Other Information" name="purchase_delivery_invoice">
|
||||
<group>
|
||||
<group name="other_info">
|
||||
<field name="user_id" domain="[('share', '=', False)]" widget="many2one_avatar_user"/>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
</group>
|
||||
<group name="invoice_info">
|
||||
<field name="invoice_status" attrs="{'invisible': [('state', 'in', ('draft', 'sent', 'to approve', 'cancel'))]}"/>
|
||||
<field name="payment_term_id" attrs="{'readonly': ['|', ('invoice_status','=', 'invoiced'), ('state', '=', 'done')]}" options="{'no_create': True}"/>
|
||||
<field name="fiscal_position_id" options="{'no_create': True}" attrs="{'readonly': ['|', ('invoice_status','=', 'invoiced'), ('state', '=', 'done')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Technical Offer Attachment">
|
||||
<field name="technical_attachment_id"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<record id="view_po_form_products_for_annual_committee" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form.products.annual_committee</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase_requisition_custom.purchase_order_custom_form_view"/>
|
||||
<field name="groups_id" eval="[(4, ref('odex25_annual_purchase.group_annual_committee'))]"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form" position="replace">
|
||||
<form>
|
||||
<header>
|
||||
<field name="can_committee_vote" invisible="1"/>
|
||||
<field name="purchase_commitee" invisible="1"/>
|
||||
<field name="requisition_id" invisible="1"/>
|
||||
<button type="object" name="action_recommend"
|
||||
groups="purchase_requisition_custom.group_select_recommended_offer"
|
||||
confirm="Are you sure you want to process ?"
|
||||
attrs="{'invisible':['|',
|
||||
('recommendation_order','=', True),('purchase_commitee', '=', False)]}" string="Recommended"/>
|
||||
<button type="object" name="action_select" groups="odex25_annual_purchase.group_annual_committee"
|
||||
attrs="{'invisible':['|', ('state','in',['done','purchase','waiting','cancel']),('can_committee_vote', '=', False)]}"
|
||||
string="Select"/>
|
||||
|
||||
<button type="object" name="action_refuse" groups="odex25_annual_purchase.group_annual_committee"
|
||||
attrs="{'invisible':['|',('state','in',['done','purchase','waiting','cancel']),('can_committee_vote', '=', False)]}"
|
||||
string="Refuse"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,sent,purchase" readonly="1"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="get_attachments" type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-file-text-o">
|
||||
<field name="attach_no" widget="statinfo" string="Documents"/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<span class="o_form_label" attrs="{'invisible': [('state','not in',('draft','sent'))]}">Request for Quotation </span>
|
||||
<span class="o_form_label" attrs="{'invisible': [('state','in',('draft','sent'))]}">Purchase Order </span>
|
||||
<h1>
|
||||
<field name="priority" widget="priority" class="mr-3"/>
|
||||
<field name="name" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<field name="recommendation_order" readonly="1" attrs="{
|
||||
'invisible': [('purchase_commitee', '=', False)]}"/>
|
||||
<field name="partner_id" />
|
||||
<field name="partner_ref" />
|
||||
<field name="annual_request_id" readonly="1"/>
|
||||
<field name="no_of_approve"/>
|
||||
</group>
|
||||
|
||||
<notebook>
|
||||
<page string="Products" name="products">
|
||||
<field name="order_line"
|
||||
widget="section_and_note_one2many"
|
||||
mode="tree,kanban"
|
||||
context="{'default_state': 'draft'}"
|
||||
attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}">
|
||||
<tree string="Purchase Order Lines" editable="bottom">
|
||||
<control>
|
||||
<create name="add_product_control" string="Add a product"/>
|
||||
<create name="add_section_control" string="Add a section" context="{'default_display_type': 'line_section'}"/>
|
||||
<create name="add_note_control" string="Add a note" context="{'default_display_type': 'line_note'}"/>
|
||||
</control>
|
||||
<field name="display_type" invisible="1"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="state" invisible="1" readonly="1"/>
|
||||
<field name="product_type" invisible="1"/>
|
||||
<field name="product_uom_category_id" invisible="1"/>
|
||||
<field name="invoice_lines" invisible="1"/>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field
|
||||
name="product_id"
|
||||
attrs="{
|
||||
'readonly': [('state', 'in', ('purchase', 'to approve','done', 'cancel'))],
|
||||
'required': [('display_type', '=', False)],
|
||||
}"
|
||||
context="{'partner_id':parent.partner_id, 'quantity':product_qty,'uom':product_uom, 'company_id': parent.company_id}"
|
||||
force_save="1" domain="[('purchase_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
|
||||
<field name="name" widget="section_and_note_text" string="Technical Description"/>
|
||||
<field name="product_qty"/>
|
||||
<field name="product_uom" string="UoM" groups="uom.group_uom"
|
||||
attrs="{
|
||||
'readonly': [('state', 'in', ('purchase', 'done', 'cancel'))],
|
||||
'required': [('display_type', '=', False)]
|
||||
}"
|
||||
force_save="1" optional="show"/>
|
||||
<field name="price_unit" attrs="{'readonly': [('invoice_lines', '!=', [])]}"/>
|
||||
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use','=','purchase'), ('company_id', '=', parent.company_id)]" context="{'default_type_tax_use': 'purchase', 'search_view_ref': 'account.account_tax_view_search'}" options="{'no_create': True}" optional="show"/>
|
||||
<field name="price_subtotal" widget="monetary"/>
|
||||
<field name="price_total" invisible="1"/>
|
||||
<field name="price_tax" invisible="1"/>
|
||||
</tree>
|
||||
<form string="Purchase Order Line">
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="display_type" invisible="1"/>
|
||||
<group attrs="{'invisible': [('display_type', '!=', False)]}">
|
||||
<group>
|
||||
<field name="product_uom_category_id" invisible="1"/>
|
||||
<field name="product_id"
|
||||
context="{'partner_id': parent.partner_id}"
|
||||
widget="many2one_barcode"
|
||||
domain="[('purchase_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"
|
||||
/>
|
||||
<label for="product_qty"/>
|
||||
<div class="o_row">
|
||||
<field name="product_qty"/>
|
||||
<field name="product_uom" groups="uom.group_uom" attrs="{'required': [('display_type', '=', False)]}"/>
|
||||
</div>
|
||||
<field name="qty_received_method" invisible="1"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use', '=', 'purchase'), ('company_id', '=', parent.company_id)]" options="{'no_create': True}"/>
|
||||
</group>
|
||||
<group colspan="12">
|
||||
<notebook>
|
||||
<page string="Notes" name="notes">
|
||||
<field name="name"/>
|
||||
</page>
|
||||
<page string="Invoices and Incoming Shipments" name="invoices_incoming_shiptments">
|
||||
<field name="invoice_lines"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</group>
|
||||
</group>
|
||||
<label for="name" string="Section Name (eg. Products, Services)" attrs="{'invisible': [('display_type', '!=', 'line_section')]}"/>
|
||||
<label for="name" string="Note" attrs="{'invisible': [('display_type', '!=', 'line_note')]}"/>
|
||||
<field name="name" nolabel="1" attrs="{'invisible': [('display_type', '=', False)]}"/>
|
||||
</form>
|
||||
</field>
|
||||
<group class="oe_subtotal_footer oe_right">
|
||||
<field name="amount_untaxed" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||
<field name="amount_tax" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||
<div class="oe_subtotal_footer_separator oe_inline">
|
||||
<label for="amount_total"/>
|
||||
</div>
|
||||
<field name="amount_total" nolabel="1" class="oe_subtotal_footer_separator" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||
</group>
|
||||
<field name="notes" class="oe_inline" placeholder="Define your terms and conditions ..."/>
|
||||
<div class="oe_clear"/>
|
||||
</page>
|
||||
|
||||
<page id="page_committee_members" string="Committee Members"
|
||||
groups="odex25_annual_purchase.group_annual_committee"
|
||||
attrs="{'invisible':['&',('requisition_id','=',False),('annual_request_id','=',False)]}">
|
||||
<field name="committe_members">
|
||||
<tree>
|
||||
<field name="user_id"/>
|
||||
<field name="selection_reason"/>
|
||||
<field name="select"/>
|
||||
<field name="refused"/>
|
||||
<field name="refusing_reason"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
<page string="Other Information" name="purchase_delivery_invoice">
|
||||
<group>
|
||||
<group name="other_info">
|
||||
<field name="user_id" domain="[('share', '=', False)]" widget="many2one_avatar_user"/>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
</group>
|
||||
<group name="invoice_info">
|
||||
<field name="invoice_status" attrs="{'invisible': [('state', 'in', ('draft', 'sent', 'to approve', 'cancel'))]}"/>
|
||||
<field name="payment_term_id" attrs="{'readonly': ['|', ('invoice_status','=', 'invoiced'), ('state', '=', 'done')]}" options="{'no_create': True}"/>
|
||||
<field name="fiscal_position_id" options="{'no_create': True}" attrs="{'readonly': ['|', ('invoice_status','=', 'invoiced'), ('state', '=', 'done')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
|
||||
</form>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<!-- Inherit the Purchase Order form -->
|
||||
<record id="purchase_order_custom_form_view" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form.custom</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="priority" eval="100"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
|
||||
<xpath expr="//form/header" position="inside">
|
||||
<field name="requisition_id" invisible="1"/>
|
||||
<field name="annual_request_id" invisible="1"/>
|
||||
<field name="is_signed" invisible="1"/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="/form/header/button[@name='print_quotation']" position="after">
|
||||
<button type="object"
|
||||
name="action_sign"
|
||||
class="oe_highlight"
|
||||
string="Sign"
|
||||
groups="purchase_requisition_custom.group_sign_purchase_order"
|
||||
attrs="{
|
||||
'invisible': [
|
||||
'|','|',
|
||||
'&', ('requisition_id','=',False), ('annual_request_id','=',False),
|
||||
('state','in',['sign','purchase','to approve','done','cancel','budget_rejected','wait_for_send','waiting']),
|
||||
('is_signed','=',True)
|
||||
]
|
||||
}"/>
|
||||
</xpath>
|
||||
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<!-- مستند التقرير (مشابه لِ purchase.report_purchasequotation_document) -->
|
||||
<template id="report_annual_rfq_document">
|
||||
<t t-call="web.external_layout">
|
||||
|
||||
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)"/>
|
||||
<div style="margin-top:50px"></div>
|
||||
|
||||
<t t-set="address">
|
||||
<strong style="display:block;"> المورد</strong> <strong style="display:block;">Vendor</strong>
|
||||
<div t-field="o.partner_id"
|
||||
t-options='{"widget": "contact", "fields": ["address", "name", "phone"], "no_marker": True, "phone_icons": True}'/>
|
||||
<p t-if="o.partner_id.vat"><t t-esc="o.company_id.country_id.vat_label or 'Tax ID'"/>: <span t-field="o.partner_id.vat"/></p>
|
||||
</t>
|
||||
|
||||
<t t-set="information_block">
|
||||
<div class="company_address mt8">
|
||||
<div>
|
||||
<strong style="display:block;">الشركة</strong>
|
||||
<strong style="display:block;">Company</strong>
|
||||
<strong t-field="o.company_id.partner_id.name"/>
|
||||
</div>
|
||||
<span t-field="o.company_id.partner_id"
|
||||
t-options='{"widget": "contact", "fields": ["address"], "no_marker": true}'/>
|
||||
</div>
|
||||
</t>
|
||||
<div class="page">
|
||||
<div class="oe_structure"/>
|
||||
|
||||
<h2>طلب عرض سعر</h2>
|
||||
<h2>#<span t-field="o.name"/></h2>
|
||||
<table class="table table-sm">
|
||||
<thead style="display: table-row-group">
|
||||
<tr>
|
||||
<th name="th_item" class="text-left">
|
||||
<span style="display:block;">item</span>
|
||||
<span style="display:block;">المنتج</span></th>
|
||||
<th name="th_description" class="text-center">
|
||||
<span style="display:block;">Description</span>
|
||||
<span style="display:block;">الوصف</span></th>
|
||||
<th name="th_quantity" class="text-center">
|
||||
<span style="display:block;">Quantity</span>
|
||||
<span style="display:block;">الكمية</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="o.line_ids" t-as="order_line">
|
||||
<tr t-att-class="'bg-200 font-weight-bold o_line_section'">
|
||||
|
||||
<td id="product" class="text-left">
|
||||
<span t-field="order_line.product_id.name"/>
|
||||
</td>
|
||||
<td id="description" class="text-center">
|
||||
<span t-field="order_line.description"/>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span t-field="order_line.quantity"/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<p style="margin-top:50px"><h3>• شروط وأحكام</h3></p>
|
||||
<p t-esc="o.notes or ''"/>
|
||||
|
||||
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- الغلاف (يمر على docs ويستدعي المستند مع لغة المورد) -->
|
||||
<template id="report_annual_rfq">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="odex25_annual_purchase.report_annual_rfq_document" t-lang="o.vendor_id.lang"/>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- إجراء التقرير -->
|
||||
<record id="action_report_annual_rfq" model="ir.actions.report">
|
||||
<field name="name">Annual RFQ</field>
|
||||
<field name="model">annual.rfq</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">odex25_annual_purchase.report_annual_rfq</field>
|
||||
<field name="report_file">odex25_annual_purchase.report_annual_rfq</field>
|
||||
<field name="print_report_name">(object.name)</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<!-- odx_rfq_committee/wizards/select_reason_rfq_views.xml -->
|
||||
<odoo>
|
||||
<record id="view_select_reason_rfq_form" model="ir.ui.view">
|
||||
<field name="name">select.reason.rfq.form</field>
|
||||
<field name="model">select.reason.rfq</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Provide Recommendation">
|
||||
<group>
|
||||
<field name="rfq_id" invisible="1"/>
|
||||
<field name="select_reason"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Submit" type="object" name="action_select" class="btn-primary"/>
|
||||
<button string="Cancel" special="cancel" class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_refuse_reason_rfq_form" model="ir.ui.view">
|
||||
<field name="name">refuse.reason.rfq.form</field>
|
||||
<field name="model">refuse.reason.rfq</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Provide Refuse Reason">
|
||||
<group>
|
||||
<field name="rfq_id" invisible="1"/>
|
||||
<field name="refuse_reason"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Submit" type="object" name="action_refuse" class="btn-primary"/>
|
||||
<button string="Cancel" special="cancel" class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -18,11 +18,7 @@ class AnnualRequestReasonWizard(models.TransientModel):
|
|||
req = self.request_id
|
||||
|
||||
if self.action_type == 'cancel':
|
||||
# نفس منطقك الحالي لإلغاء أوامر الشراء المرتبطة
|
||||
related_orders = self.env['purchase.order'].search([('annual_request_id', '=', req.id)])
|
||||
for order in related_orders:
|
||||
if order.state:
|
||||
order.button_cancel()
|
||||
|
||||
req.message_post(body=_("Reason: %s") % self.reason)
|
||||
vals = {'state': 'cancel'}
|
||||
if 'cancel_reason' in req._fields:
|
||||
|
|
|
|||
Loading…
Reference in New Issue