This commit is contained in:
mohammed-alkhazrji 2025-12-03 02:02:34 +03:00
parent 3c266feda8
commit 8301725965
6 changed files with 293 additions and 75 deletions

View File

@ -1,33 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<data >
<record id="email_template_annual_rfq_new" 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">طلب عرض سعر ${object.name or ''}</field>
<field name="subject">Request for Quotation ${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; font-family: Arial, sans-serif; direction: rtl; text-align: right;">
السادة ${object.vendor_id.name}
<div style="margin: 0px; padding: 0px; font-size: 13px; font-family: Arial, sans-serif;">
<p style="margin: 0px; padding: 0px;">
Dear ${object.vendor_id.name}
% if object.vendor_id.parent_id:
(${object.vendor_id.parent_id.name})
% endif
<br/><br/>
يُرفق إليكم طلب عرض السعر الخاص بالطلب رقم <strong>${object.name}</strong>
Please find attached the request for quotation for order <strong>${object.name}</strong>
% if object.partner_ref:
بالمرجع: ${object.partner_ref}
Reference: ${object.partner_ref}
% endif
من ${object.company_id.name}.
from ${object.company_id.name}.
<br/><br/>
في حال وجود أي استفسارات، لا تترددوا في التواصل معنا بالرد على هذا الايميل .
If you have any questions, please feel free to reply to this email.
<br/><br/>
مع أطيب التحيات،
Best regards,
</p>
</div></field>
</div>
</field>
<field name="report_template" ref="action_report_annual_rfq"/>
<field name="report_name">${(object.name or '').replace('/','_')}</field>
<field name="lang">ar</field>
<field name="lang">${object.vendor_id.lang or object.partner_id.lang or 'en_US'}</field>
<field name="auto_delete" eval="True"/>
</record>
</data>
</odoo>
<!--<?xml version="1.0" encoding="utf-8"?>-->
<!--<odoo>-->
<!-- <data noupdate="1">-->
<!-- <record id="email_template_annual_rfq_new" 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">طلب عرض سعر ${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; font-family: Arial, sans-serif; direction: rtl; text-align: right;">-->
<!-- السادة ${object.vendor_id.name}-->
<!-- % if object.vendor_id.parent_id:-->
<!-- (${object.vendor_id.parent_id.name})-->
<!-- % endif-->
<!-- <br/><br/>-->
<!-- يُرفق إليكم طلب عرض السعر الخاص بالطلب رقم <strong>${object.name}</strong>-->
<!-- % if object.partner_ref:-->
<!-- بالمرجع: ${object.partner_ref}-->
<!-- % endif-->
<!-- من ${object.company_id.name}.-->
<!-- <br/><br/>-->
<!-- في حال وجود أي استفسارات، لا تترددوا في التواصل معنا بالرد على هذا الايميل .-->
<!-- <br/><br/>-->
<!-- مع أطيب التحيات،-->
<!-- </p>-->
<!--</div></field>-->
<!-- <field name="report_template" ref="action_report_annual_rfq"/>-->
<!-- <field name="report_name">${(object.name or '').replace('/','_')}</field>-->
<!-- <field name="lang">ar</field>-->
<!-- <field name="auto_delete" eval="True"/>-->
<!-- </record>-->
<!-- </data>-->
<!--</odoo>-->

View File

@ -1292,3 +1292,49 @@ msgstr "إعادة إرسال طلب عرض سعر"
#. module: odex25_annual_purchase
#: model:mail.template,body_html:odex25_annual_purchase.email_template_annual_rfq_new
msgid ""
"<div style=\"margin: 0px; padding: 0px; font-size: 13px; font-family: Arial, sans-serif;\">\n"
" <p style=\"margin: 0px; padding: 0px;\">\n"
" Dear ${object.vendor_id.name}\n"
" % if object.vendor_id.parent_id:\n"
" (${object.vendor_id.parent_id.name})\n"
" % endif\n"
" <br/><br/>\n"
" Please find attached the request for quotation for order <strong>${object.name}</strong>\n"
" % if object.partner_ref:\n"
" Reference: ${object.partner_ref}\n"
" % endif\n"
" from ${object.company_id.name}.\n"
" <br/><br/>\n"
" If you have any questions, please feel free to reply to this email.\n"
" <br/><br/>\n"
" Best regards,\n"
" </p>\n"
"</div>\n"
" "
msgstr ""
"<div style=\"margin: 0px; padding: 0px; font-size: 13px; font-family: Arial, sans-serif; direction: rtl; text-align: right;\">\n"
" <p style=\"margin: 0px; padding: 0px;\">\n"
" السادة/ ${object.vendor_id.name}\n"
" % if object.vendor_id.parent_id:\n"
" (${object.vendor_id.parent_id.name})\n"
" % endif\n"
" <br/><br/>\n"
" نرجو منكم التكرّم بالاطلاع على طلب عرض السعر المرفق الخاص بالطلب رقم <strong>${object.name}</strong>\n"
" % if object.partner_ref:\n"
" (المرجع: ${object.partner_ref})\n"
" % endif\n"
" والتابع لـ ${object.company_id.name}.\n"
" <br/><br/>\n"
" في حال وجود أي استفسارات، يُرجى عدم التردد في التواصل معنا عبر الرد على هذا البريد.\n"
" <br/><br/>\n"
" مع خالص التحية والتقدير،\n"
" </p>\n"
"</div>"
#. module: odex25_annual_purchase
#: model:mail.template,subject:odex25_annual_purchase.email_template_annual_rfq_new
msgid "Request for Quotation ${object.name or ''}"
msgstr "طلب عرض سعر ${object.name or ''}"

View File

@ -76,6 +76,23 @@ class PurchaseRFQ(models.Model):
string="Technical Attachments",
help="Upload technical offer documents here"
)
@api.model
def _get_picking_type(self, company_id):
picking_type = self.env['stock.picking.type'].search([('code', '=', 'incoming'), ('warehouse_id.company_id', '=', company_id)])
if not picking_type:
picking_type = self.env['stock.picking.type'].search([('code', '=', 'incoming'), ('warehouse_id', '=', False)])
return picking_type[:1]
@api.model
def _default_picking_type(self):
return self._get_picking_type(self.env.context.get('company_id') or self.env.company.id)
dest_address_id = fields.Many2one('res.partner', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", string='Drop Ship Address',
help="Put an address if you want to deliver directly from the vendor to the customer. "
"Otherwise, keep empty to deliver to your own company.")
picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To', required=True, default=_default_picking_type, domain="['|', ('warehouse_id', '=', False), ('warehouse_id.company_id', '=', company_id)]",
help="This will determine operation type of incoming shipment")
@api.depends('committe_members')
def _compute_no_approve(self):
for rec in self:
@ -90,7 +107,22 @@ class PurchaseRFQ(models.Model):
and rec.purchase_commitee
and rec.state in ('committee', 'draft', 'sent')
)
@api.model
def default_get(self, fields):
res = super(PurchaseRFQ, self).default_get(fields)
if self._context.get('default_source_request_ref'):
request = self.env['odx.annual.request'].browse(self._context['default_source_request_ref'])
lines = []
for l in request.line_ids:
lines.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,
}))
res['line_ids'] = lines
return res
@api.model
def copy(self, default=None):
@ -133,25 +165,31 @@ class PurchaseRFQ(models.Model):
def action_refuse_rfq(self):
self.ensure_one()
member = self.committe_members.filtered(lambda m: m.user_id == self.env.user)
if member and member.refused:
raise UserError(_("You have already refused this RFQ before."))
member = self.env['committe.member'].search([
('rfq_id', '=', self.id),
('user_id', '=', self.env.user.id),
], limit=1)
vals = {
'refused': True,
'select': False,
'selection_reason': False,
}
if member:
member.write(vals)
else:
self.env['committe.member'].create({
'rfq_id': self.id,
'user_id': self.env.user.id,
'refused': True,
'select': False
**vals
})
self._check_committee_rejection()
return {
'type': 'ir.actions.act_window',
'name': _('Select Reason'),
'name': _('Refuse Reason'),
'res_model': 'refuse.reason.rfq',
'view_mode': 'form',
'target': 'new',
@ -160,6 +198,35 @@ class PurchaseRFQ(models.Model):
}
}
# def action_refuse_rfq(self):
# self.ensure_one()
# member = self.committe_members.filtered(lambda m: m.user_id == self.env.user)
#
# if member and member.refused:
# raise UserError(_("You have already refused this RFQ before."))
#
#
# else:
# self.env['committe.member'].create({
# 'rfq_id': self.id,
# 'user_id': self.env.user.id,
# 'refused': True,
# 'select': False
# })
#
# self._check_committee_rejection()
#
# return {
# 'type': 'ir.actions.act_window',
# 'name': _('Select Reason'),
# 'res_model': 'refuse.reason.rfq',
# 'view_mode': 'form',
# 'target': 'new',
# 'context': {
# 'default_rfq_id': self.id
# }
# }
def _check_committee_rejection(self):
@ -250,7 +317,7 @@ class PurchaseRFQ(models.Model):
'default_use_template': bool(template),
'default_template_id': template.id if template else False,
'default_composition_mode': 'comment',
'custom_layout': "mail.mail_notification_paynow",
# 'custom_layout': "mail.mail_notification_paynow",
'force_email': True,
'mail_post_autofollow': True,

View File

@ -76,6 +76,8 @@
<field name="department_id" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="product_category_ids" widget="many2many_tags" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="date" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="date_start" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="date_end" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="ssd_approve" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="seo_approve" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
@ -84,8 +86,6 @@
<field name="employee_id" readonly="1"/>
<field name="user_id" invisible="1"/>
<field name="purpose" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="date_start" invisible="1"/>
<field name="date_end" invisible="1"/>
<field name="vendor_id" invisible="1"/>
<field name="committee_enabled" attrs="{'readonly': [('state', '!=', 'draft')]}"/>

View File

@ -131,6 +131,15 @@
<field name="user_id"/>
</group>
</page>
<page string="العرض الفني" id="page_technical_offer"
groups="purchase.group_purchase_user,odex25_annual_purchase.group_technical_committee"
>
<group>
<field name="technical_attachment_ids" widget="many2many_binary"
string="Technical Attachments"
help="Upload technical offer documents here"/>
</group>
</page>
</notebook>
</sheet>
@ -166,15 +175,8 @@
<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>

View File

@ -2,77 +2,144 @@
<odoo>
<data>
<!-- ====================== تقرير RFQ ======================== -->
<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>
<!-- ===================== HEADER ===================== -->
<table style="width: 100%; margin: 20px 0;">
<tr>
<t t-set="information_block">
<div class="company_address mt8">
<div>
<strong style="display:block;">الشركة</strong>
<strong style="display:block;">Company</strong>
<!-- ====== الشركة ====== -->
<td style="width: 33%; vertical-align: top;">
<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"/>
<span t-field="o.company_id.partner_id"
t-options='{"widget": "contact", "fields": ["address"], "no_marker": true}'/>
<h2>طلب عرض سعر</h2>
<h2>#<span t-field="o.name"/></h2>
<p t-if="o.company_id.partner_id.vat" style="margin: 0;">
<t t-esc="o.company_id.country_id.vat_label or 'Tax ID'"/>:
<span t-field="o.company_id.partner_id.vat"/>
</p>
</td>
<!-- ====== عنوان التقرير ====== -->
<td style="width: 33%; font-size: 15px; padding-left: 50px;">
<h2 class="text-center" style="margin: 2;font-size: 26px;">طلب عرض سعر</h2>
<h1 class="text-center" style="margin: 2;font-size: 30px;">
#<span t-field="o.name"/>
</h1>
</td>
<!-- ====== بيانات المورد ====== -->
<td style="width: 33%; vertical-align: top;">
<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" style="margin: 0;">
<t t-esc="o.company_id.country_id.vat_label or 'Tax ID'"/>:
<span t-field="o.partner_id.vat"/>
</p>
</td>
</tr>
</table>
<!-- ================ المحتوى الرئيسي ================== -->
<div class="page o_report_layout_background o_standard_font">
<!-- مندوب المشتريات -->
<t t-if="o.user_id">
<div class="col-5 bm-2" style="margin-bottom:20px;">
<strong>مندوب المشتريات</strong>
<strong style="display:block;">Purchase Representative:</strong>
<table>
<tr>
<td><p t-field="o.user_id" class="m-0"/></td>
<td>
<p t-field="o.user_id.login"
class="m-0"
style="padding-left: 10px; font-size: 11px;"/>
</td>
</tr>
</table>
</div>
</t>
<!-- ================= جدول الطلب ================= -->
<table class="table table-sm">
<thead style="display: table-row-group">
<tr>
<th name="th_item" class="text-left">
<th class="text-center">
<span style="display:block;">item</span>
<span style="display:block;">المنتج</span></th>
<th name="th_description" class="text-center">
<span style="display:block;">المنتج</span>
</th>
<th 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;">الوصف</span>
</th>
<th class="text-center">
<span style="display:block;">Quantity</span>
<span style="display:block;">الكمية</span></th>
<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>
<tbody>
<t t-foreach="o.line_ids" t-as="line">
<tr>
<td class="text-center">
<span t-field="line.product_id.name"/>
</td>
<td class="text-center">
<span t-field="line.description"/>
</td>
<td class="text-center">
<span t-field="line.quantity"/>
</td>
</tr>
</t>
</tbody>
</table>
<p style="margin-top:50px"><h3>• شروط وأحكام</h3></p>
<!-- ================= شروط وأحكام ================= -->
<h3 style="margin-top:60px;">• شروط وأحكام</h3>
<p t-esc="o.notes or ''"/>
<!-- ============ عنوان الشحن ============ -->
<div class="row" style="margin-top: 80px;">
<div class="col-6" style="font-size:11px;">
<t t-if="o.dest_address_id">
<strong style="display:block; font-size:14px;">عنوان الشحن</strong>
<strong style="display:block; font-size:12px;">Shipping address</strong>
<p style="font-size:10px;" t-field="o.dest_address_id"/>
</t>
<t t-if="not o.dest_address_id and o.picking_type_id.warehouse_id">
<strong style="display:block; font-size:14px;">عنوان الشحن</strong>
<strong style="display:block; font-size:12px;">Shipping address</strong>
<p style="font-size:10px;">
<span t-esc="o.picking_type_id.warehouse_id.name"/>
</p>
</t>
</div>
</div>
<div class="oe_structure"/>
</div>
</t>
</template>
<!-- =============== غلاف التقرير الأساسي ================== -->
<template id="report_annual_rfq">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">