| @ -0,0 +1,48 @@ | |||
| .. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg | |||
|     :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html | |||
|     :alt: License: AGPL-3 | |||
| 
 | |||
| Purchase Recurring Orders | |||
| ========================= | |||
| This module allows you to create recurring orders for purchases. | |||
| 
 | |||
| Configuration | |||
| ============= | |||
| No additional configuration required | |||
| 
 | |||
| Company | |||
| ------- | |||
| * `Cybrosys Techno Solutions <https://cybrosys.com/>`__ | |||
| 
 | |||
| License | |||
| ------- | |||
| Affero General Public License v3.0 (AGPL v3) | |||
| 
 | |||
| https://www.gnu.org/licenses/agpl-3.0-standalone.html | |||
| 
 | |||
| Credits | |||
| ------- | |||
| Developer: (V14) Ruksana P, Contact:odoo@cybrosys.com | |||
| 
 | |||
| Contacts | |||
| -------- | |||
| * Mail Contact : odoo@cybrosys.com | |||
| * Website : https://cybrosys.com | |||
| 
 | |||
| Bug Tracker | |||
| ----------- | |||
| Bugs are tracked on GitHub Issues. In case of trouble, please check there if | |||
| your issue has already been reported. | |||
| 
 | |||
| Maintainer | |||
| ========== | |||
| .. image:: https://cybrosys.com/images/logo.png | |||
|    :target: https://cybrosys.com | |||
| 
 | |||
| This module is maintained by Cybrosys Technologies. | |||
| 
 | |||
| For support and more information, please visit `Our Website <https://cybrosys.com/>`__ | |||
| 
 | |||
| Further information | |||
| =================== | |||
| HTML Description: `<static/description/index.html>`__ | |||
| @ -0,0 +1,23 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| from . import models | |||
| from . import wizards | |||
| @ -0,0 +1,48 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| { | |||
|     'name': 'Purchase Recurring Orders', | |||
|     'version': '14.0.1.0.0', | |||
|     'category': 'Purchases', | |||
|     'summary': 'Helps to create purchase recurring orders', | |||
|     'description': """ This module Helps to create recurring orders for  | |||
|      Purchases based on the information provided.""", | |||
|     'author': 'Cybrosys Techno Solutions', | |||
|     'company': 'Cybrosys Techno Solutions', | |||
|     'maintainer': 'Cybrosys Techno Solutions', | |||
|     'website': 'https://www.cybrosys.com', | |||
|     'depends': ['purchase'], | |||
|     'data': [ | |||
|         'security/ir.model.access.csv', | |||
|         'data/ir_cron_data.xml', | |||
|         'data/ir_sequence_data.xml', | |||
|         'wizards/agreement_renewal_views.xml', | |||
|         'views/purchase_recurring_agreement_views.xml', | |||
|         'views/purchase_order_views.xml', | |||
|         'views/res_partner_views.xml', | |||
|     ], | |||
|     'images': ['static/description/banner.png'], | |||
|     'license': 'AGPL-3', | |||
|     'installable': True, | |||
|     'auto_install': False, | |||
|     'application': False, | |||
| } | |||
| @ -0,0 +1,44 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <odoo noupdate="1"> | |||
|     <!--      Scheduled Action for Prolongation check of recurring orders | |||
|     agreements--> | |||
|     <record id="ir_cron_recurring_orders_prolong_check" model="ir.cron"> | |||
|         <field name="name">Prolongation Check for Recurring Orders | |||
|             Agreements | |||
|         </field> | |||
|         <field name="model_id" ref="model_purchase_recurring_agreement"/> | |||
|         <field name="type">ir.actions.server</field> | |||
|         <field name="state">code</field> | |||
|         <field name="code">model.revise_agreements_expirations_planned() | |||
|         </field> | |||
|         <field name="interval_number">1</field> | |||
|         <field name="doall" eval="False"/> | |||
|         <field name="interval_type">days</field> | |||
|         <field name="numbercall">-1</field> | |||
|     </record> | |||
|     <!--      Scheduled Action for Confirming current orders--> | |||
|     <record id="ir_cron_recurring_orders_confirm_orders" model="ir.cron"> | |||
|         <field name="name">Confirm Current Orders</field> | |||
|         <field name="model_id" ref="model_purchase_recurring_agreement"/> | |||
|         <field name="type">ir.actions.server</field> | |||
|         <field name="state">code</field> | |||
|         <field name="code">model.confirm_current_orders_planned()</field> | |||
|         <field name="interval_number">1</field> | |||
|         <field name="doall" eval="False"/> | |||
|         <field name="interval_type">days</field> | |||
|         <field name="numbercall">-1</field> | |||
|     </record> | |||
|     <!--      Scheduled Action for Generating recurring orders for next | |||
|     year--> | |||
|     <record id="ir_cron_recurring_orders_generate_orders" model="ir.cron"> | |||
|         <field name="name">Generate Recurring Orders for Next Year</field> | |||
|         <field name="model_id" ref="model_purchase_recurring_agreement"/> | |||
|         <field name="type">ir.actions.server</field> | |||
|         <field name="state">code</field> | |||
|         <field name="code">model.generate_next_orders_planned()</field> | |||
|         <field name="interval_number">1</field> | |||
|         <field name="interval_type">days</field> | |||
|         <field name="numbercall">-1</field> | |||
|     </record> | |||
| </odoo> | |||
| 
 | |||
| @ -0,0 +1,11 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <odoo noupdate="1"> | |||
|     <!--  Sequence Generator--> | |||
|     <record model="ir.sequence" id="ir_sequence_recurring_agreement"> | |||
|         <field name="name">Agreement Sequence</field> | |||
|         <field name="code">purchase.r_o.agreement.sequence</field> | |||
|         <field name="padding">4</field> | |||
|         <field name="prefix">AG-%(y)s-</field> | |||
|         <field name="company_id" eval="False"/> | |||
|     </record> | |||
| </odoo> | |||
| @ -0,0 +1,6 @@ | |||
| ## Module <purchase_recurring_orders> | |||
| 
 | |||
| #### 14.08.2023 | |||
| #### Version 14.0.1.0.0 | |||
| #### ADD | |||
| - Initial commit for Purchase Recurring Orders | |||
| @ -0,0 +1,26 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| from . import agreement_renewal_line | |||
| from . import purchase_order | |||
| from . import purchase_recurring_agreement | |||
| from . import recurring_agreement_line | |||
| from . import res_partner | |||
| @ -0,0 +1,36 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| from odoo import fields, models | |||
| 
 | |||
| 
 | |||
| class AgreementRenewalLine(models.Model): | |||
|     """ Purchase recurring agreement renewal records """ | |||
|     _name = 'agreement.renewal.line' | |||
|     _description = "Purchase Agreement Renewal Records" | |||
| 
 | |||
|     recurring_agreement_id = fields.Many2one('purchase.recurring.agreement', | |||
|                                              string='Agreement Reference', | |||
|                                              ondelete='cascade', | |||
|                                              help='Recurring agreement for ' | |||
|                                                   'renewal') | |||
|     date = fields.Datetime(string='Date', help="Date of the Renewal") | |||
|     comments = fields.Char(string='Comments', size=200, help='Renewal comments') | |||
| @ -0,0 +1,83 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P  (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| from odoo import api, fields, models | |||
| 
 | |||
| 
 | |||
| class PurchaseOrder(models.Model): | |||
|     """ Purchase order inherited for adding two fields is_agreement and | |||
|      recurring_agreement_id """ | |||
|     _inherit = 'purchase.order' | |||
| 
 | |||
|     is_agreement = fields.Boolean(string='From Agreement?', copy=False, | |||
|                                   help="Checking this box represents that " | |||
|                                        "purchase order is from agreement.") | |||
|     recurring_agreement_id = fields.Many2one('purchase.recurring.agreement', | |||
|                                              string='Agreement Reference', | |||
|                                              help="This indicates the Purchase" | |||
|                                                   " Agreement", | |||
|                                              ondelete='restrict') | |||
| 
 | |||
|     @api.model | |||
|     def _prepare_agreement_vals(self, order): | |||
|         """ Method for creating agreement values""" | |||
|         return { | |||
|             'partner_id': order.partner_id.id, | |||
|             'company_id': order.company_id.id, | |||
|             'start_date': fields.Datetime.now(), | |||
|         } | |||
| 
 | |||
|     @api.model | |||
|     def _prepare_agreement_line_vals(self, order_ids, agreement): | |||
|         """ Returns the Agreement Line Values in a Dictionary Format""" | |||
|         return { | |||
|             'recurring_agreement_id': agreement.id, | |||
|             'product_id': order_ids.product_id.id, | |||
|             'quantity': order_ids.product_qty, | |||
|         } | |||
| 
 | |||
|     def action_generate_agreement(self): | |||
|         """Generates Purchase Recurring Agreement""" | |||
|         agreements = [] | |||
|         for purchase_order in self: | |||
|             agreement_vals = self._prepare_agreement_vals(purchase_order) | |||
|             agreement = self.env[ | |||
|                 'purchase.recurring.agreement'].create(agreement_vals) | |||
|             agreements.append(agreement) | |||
|             for order_id in purchase_order.order_line: | |||
|                 agreement_line_vals = self._prepare_agreement_line_vals( | |||
|                     order_id, agreement) | |||
|                 self.env['recurring.agreement.line'].create(agreement_line_vals) | |||
|         if len(agreements) == 1: | |||
|             view = self.env.ref( | |||
|                 'purchase_recurring_orders.' | |||
|                 'purchase_recurring_agreement_view_form') | |||
|             return { | |||
|                 'type': 'ir.actions.act_window', | |||
|                 'view_mode': 'form', | |||
|                 'res_model': 'purchase.recurring.agreement', | |||
|                 'views': [(view.id, 'form')], | |||
|                 'view_id': view.id, | |||
|                 'target': 'new', | |||
|                 'res_id': agreement[0].id, | |||
|                 'nodestroy': True, | |||
|             } | |||
|         return True | |||
| @ -0,0 +1,403 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| from datetime import timedelta | |||
| from dateutil.relativedelta import relativedelta | |||
| from odoo import api, exceptions, fields, models, _ | |||
| 
 | |||
| 
 | |||
| class PurchaseRecurringAgreement(models.Model): | |||
|     """Model for generating purchase recurring agreement""" | |||
|     _name = 'purchase.recurring.agreement' | |||
|     _inherit = 'mail.thread' | |||
|     _description = "Purchase Recurring Agreement" | |||
| 
 | |||
|     def _default_company_id(self): | |||
|         """Returns the Current Company id""" | |||
|         company = self.env['res.company']._company_default_get('purchase') | |||
|         return company | |||
| 
 | |||
|     name = fields.Char(string='Sequence Number', index=True, size=32, | |||
|                        help="Number of agreement. Keep empty to get the " | |||
|                             "number assigned by a sequence.", copy=False, | |||
|                        default=_('New'), readonly=True) | |||
|     active = fields.Boolean(string='Active', default=True, | |||
|                             help='Unchecking this field, quotation for ' | |||
|                                  'corresponding product is not generated') | |||
|     partner_id = fields.Many2one('res.partner', string='Supplier', index=True, | |||
|                                  change_default=True, required=True, | |||
|                                  help="Supplier you are making the agreement") | |||
|     company_id = fields.Many2one('res.company', string='Company', required=True, | |||
|                                  help="Company that signs the agreement", | |||
|                                  default=_default_company_id) | |||
|     start_date = fields.Date(string='Start Date', index=True, copy=False, | |||
|                              help="Beginning of the agreement. Keep empty to " | |||
|                                   "use the current date") | |||
|     prolong = fields.Selection( | |||
|         selection=[('recurrent', 'Renewable Fixed Term'), | |||
|                    ('unlimited', 'Unlimited Term'), | |||
|                    ('fixed', 'Fixed Term')], | |||
|         string='Prolongation', default='unlimited', | |||
|         help="Sets the term of the agreement. 'Renewable fixed term': It sets " | |||
|              "a fixed term, but with possibility of manual renew; 'Unlimited " | |||
|              "term': Renew is made automatically; 'Fixed term': The term is " | |||
|              "fixed and there is no possibility to renew.") | |||
|     end_date = fields.Date(string='End date', help="End Date of the Agreement") | |||
|     prolong_interval = fields.Integer( | |||
|         string='Interval', default=1, | |||
|         help="Interval in time units to prolong the agreement until new " | |||
|              "renewable (that is automatic for unlimited term, manual for " | |||
|              "renewable fixed term).") | |||
|     prolong_unit = fields.Selection([('days', 'Days'), ('weeks', 'Weeks'), | |||
|                                      ('months', 'Months'), ('years', 'Years')], | |||
|                                     string='Interval Unit', default='years', | |||
|                                     help='Time unit for the prolongation ' | |||
|                                          'interval') | |||
|     agreement_line_ids = fields.One2many('recurring.agreement.line', | |||
|                                          inverse_name='recurring_agreement_id', | |||
|                                          string='Agreement Lines', | |||
|                                          help='Agreement product records') | |||
|     order_ids = fields.One2many('purchase.order', copy=False, readonly=True, | |||
|                                 inverse_name='recurring_agreement_id', | |||
|                                 string='Orders') | |||
|     renewal_ids = fields.One2many('agreement.renewal.line', readonly=True, | |||
|                                   copy=False, sring='Renewal Lines', | |||
|                                   help='Renewal records', | |||
|                                   inverse_name='recurring_agreement_id') | |||
|     last_renovation_date = fields.Datetime( | |||
|         string='Last Renovation Date', | |||
|         help="Last date when agreement was renewed (same as start date if not " | |||
|              "renewed)") | |||
|     next_expiration_date = fields.Datetime( | |||
|         compute="_compute_next_expiration_date", | |||
|         help="Date when agreement will expired ", | |||
|         string='Next Expiration Date') | |||
|     state = fields.Selection([('empty', 'Without Orders'), | |||
|                               ('first', 'First Order Created'), | |||
|                               ('orders', 'With Orders')], string='State', | |||
|                              readonly=True, default='empty', | |||
|                              help="Indicates the state of recurring agreement") | |||
|     renewal_state = fields.Selection([('not_renewed', 'Agreement not Renewed'), | |||
|                                       ('renewed', 'Agreement Renewed')], | |||
|                                      string='Renewal State', readonly=True, | |||
|                                      help="Renewal status of the recurring" | |||
|                                           " agreement", default='not_renewed') | |||
|     notes = fields.Text('Notes', help="Notes regarding renewal agreement") | |||
|     order_count = fields.Integer(compute='_compute_order_count', | |||
|                                  string='Order Count', | |||
|                                  help="Indicates the no. of orders generated " | |||
|                                       "with this agreement") | |||
|     _sql_constraints = [ | |||
|         ('name_uniq', 'unique(name)', 'Agreement Number Must be Unique !'), | |||
|     ] | |||
| 
 | |||
|     @api.model | |||
|     def _get_next_term_date(self, date, unit, interval): | |||
|         """Returns the Next Term Date""" | |||
|         if unit == 'days': | |||
|             date = date + timedelta(days=interval) | |||
|         elif unit == 'weeks': | |||
|             date = date + timedelta(weeks=interval) | |||
|         elif unit == 'months': | |||
|             date = date + relativedelta(months=interval) | |||
|         elif unit == 'years': | |||
|             date = date + relativedelta(years=interval) | |||
|         return date | |||
| 
 | |||
|     def _compute_next_expiration_date(self): | |||
|         """Calculates the Next Expiration Date According to the Prolongation | |||
|         Unit Chosen""" | |||
|         for agreement in self: | |||
|             if agreement.prolong == 'fixed': | |||
|                 agreement.next_expiration_date = agreement.end_date | |||
|             elif agreement.prolong == 'unlimited': | |||
|                 now = fields.Date.from_string(fields.Datetime.today()) | |||
|                 date = self._get_next_term_date( | |||
|                     fields.Date.from_string(agreement.start_date), | |||
|                     agreement.prolong_unit, agreement.prolong_interval) | |||
|                 while date < now: | |||
|                     date = self._get_next_term_date( | |||
|                         date, agreement.prolong_unit, | |||
|                         agreement.prolong_interval) | |||
|                 agreement.next_expiration_date = date | |||
|             else: | |||
|                 agreement.next_expiration_date = self._get_next_term_date( | |||
|                     fields.Datetime.from_string( | |||
|                         agreement.last_renovation_date or | |||
|                         agreement.start_date), | |||
|                     agreement.prolong_unit, agreement.prolong_interval) | |||
| 
 | |||
|     def _compute_order_count(self): | |||
|         """Finds the count of orders generated from the Agreement""" | |||
|         for record in self: | |||
|             record.order_count = self.env['purchase.order'].search_count( | |||
|                 [('recurring_agreement_id', '=', self.id)]) | |||
| 
 | |||
|     @api.constrains('start_date', 'end_date') | |||
|     def _check_dates(self): | |||
|         """Method for ensuring start date will be always less than | |||
|          or equal to end date""" | |||
|         for record in self: | |||
|             if record.end_date and record.end_date < record.start_date: | |||
|                 raise exceptions.Warning( | |||
|                     _('Agreement End Date must be Greater than Start Date')) | |||
| 
 | |||
|     @api.model | |||
|     def create(self, vals): | |||
|         """Function that supering create function""" | |||
|         if not vals.get('start_date'): | |||
|             vals['start_date'] = fields.Datetime.today() | |||
|         if vals.get('name', _('New')) == _('New'): | |||
|             vals['name'] = self.env['ir.sequence'].get( | |||
|                 'purchase.r_o.agreement.sequence') | |||
|         return super().create(vals) | |||
| 
 | |||
|     def write(self, vals): | |||
|         """Function that supering write function""" | |||
|         value = super().write(vals) | |||
|         if (any(vals.get(x) is not None for x in | |||
|                 ['active', 'name', 'agreement_line_ids', 'prolong', | |||
|                  'end_date', | |||
|                  'prolong_interval', 'prolong_unit', 'partner_id'])): | |||
|             self.unlink_orders(fields.Datetime.today()) | |||
|         return value | |||
| 
 | |||
|     @api.returns('self', lambda value: value.id) | |||
|     def copy(self, default=None): | |||
|         default = dict(default or {}) | |||
|         if 'name' not in default: | |||
|             default['name'] = _("%s (Copy)") % self.name | |||
|         return super().copy(default=default) | |||
| 
 | |||
|     def unlink(self): | |||
|         """Function that supering unlink function which will unlink Self and | |||
|         the Current record""" | |||
|         for agreement in self: | |||
|             if any(agreement.mapped('order_ids')): | |||
|                 raise exceptions.Warning( | |||
|                     _('You Cannot Remove Agreements with Confirmed Orders!')) | |||
|         self.unlink_orders(fields.Datetime.from_string(fields.Datetime.today())) | |||
|         return models.Model.unlink(self) | |||
| 
 | |||
|     @api.onchange('start_date') | |||
|     def _onchange_last_renovation_date(self): | |||
|         """Method for updating last renovation date""" | |||
|         self.last_renovation_date = self.start_date | |||
| 
 | |||
|     @api.model | |||
|     def revise_agreements_expirations_planned(self): | |||
|         """Method for changing the prolong as unlimited""" | |||
|         for agreement in self.search([('prolong', '=', 'unlimited')]): | |||
|             if agreement.next_expiration_date <= fields.Datetime.today(): | |||
|                 agreement.write({'prolong': 'unlimited'}) | |||
|         return True | |||
| 
 | |||
|     @api.model | |||
|     def _prepare_purchase_order_vals(self, agreement, date): | |||
|         """Creates purchase order values""" | |||
|         # Order Values | |||
|         order_vals = {'date_order': date, | |||
|                       'origin': agreement.name, | |||
|                       'partner_id': agreement.partner_id.id, | |||
|                       'state': 'draft', 'company_id': agreement.company_id.id, | |||
|                       'is_agreement': True, | |||
|                       'recurring_agreement_id': agreement.id, | |||
|                       'date_planned': date, | |||
|                       'payment_term_id': agreement.partner_id. | |||
|                       property_supplier_payment_term_id.id, | |||
|                       'currency_id': | |||
|                           agreement.partner_id.property_purchase_currency_id.id | |||
|                           or self.env.user.company_id.currency_id.id, | |||
|                       'user_id': agreement.partner_id.user_id.id} | |||
|         return order_vals | |||
| 
 | |||
|     @api.model | |||
|     def _prepare_purchase_order_line_vals(self, agreement_line_ids, order): | |||
|         """Returns the Purchase Order Line Values as a Dictionary Which can be | |||
|          Used While creating the Purchase Order""" | |||
|         product = agreement_line_ids.product_id | |||
|         product_lang = product.with_context({ | |||
|             'lang': order.partner_id.lang, | |||
|             'partner_id': order.partner_id.id, | |||
|         }) | |||
|         fpos = order.fiscal_position_id | |||
|         # Order Line Values as a Dictionary | |||
|         order_line_vals = { | |||
|             'order_id': order.id, | |||
|             'product_id': product.id, | |||
|             'product_qty': agreement_line_ids.quantity, | |||
|             'date_planned': order.date_planned, | |||
|             'price_unit': product._get_tax_included_unit_price( | |||
|                 order.company_id, order.currency_id, order.date_order, | |||
|                 'purchase', | |||
|                 fiscal_position=order.fiscal_position_id, | |||
|                 product_uom=product.uom_po_id), | |||
|             'product_uom': product.uom_po_id.id or product.uom_id.id, | |||
|             'name': product_lang.display_name, | |||
|             'taxes_id': fpos.map_tax( | |||
|                 product.supplier_taxes_id.filtered( | |||
|                     lambda r: r.company_id.id == self.company_id.id).ids) | |||
|         } | |||
|         # product price changed if specific price is added | |||
|         if agreement_line_ids.specific_price: | |||
|             order_line_vals['price_unit'] = agreement_line_ids.specific_price | |||
|         order_line_vals['taxes_id'] = [ | |||
|             (6, 0, tuple(order_line_vals['taxes_id']))] | |||
|         # product price changed if specific price is added | |||
|         if agreement_line_ids.additional_description: | |||
|             order_line_vals['name'] += " %s" % ( | |||
|                 agreement_line_ids.additional_description) | |||
|         return order_line_vals | |||
| 
 | |||
|     def create_order(self, date, agreement_lines): | |||
|         """Create Purchase Order from Recurring Agreement """ | |||
|         self.ensure_one() | |||
|         order_line_obj = self.env['purchase.order.line'].with_context( | |||
|             company_id=self.company_id.id) | |||
|         order_vals = self._prepare_purchase_order_vals(self, date) | |||
|         order = self.env['purchase.order'].create(order_vals) | |||
|         for agreement_line in agreement_lines: | |||
|             # Create Purchase Order Line Values | |||
|             order_line_vals = self._prepare_purchase_order_line_vals( | |||
|                 agreement_line, order) | |||
|             order_line_obj.create(order_line_vals) | |||
|         agreement_lines.write({'last_order_date': fields.Datetime.today()}) | |||
|         if self.state != 'orders': | |||
|             self.state = 'orders' | |||
|         return order | |||
| 
 | |||
|     def _get_next_order_date(self, line, start_date): | |||
|         """Return The date of Next Purchase order generated from the | |||
|          Agreement""" | |||
|         self.ensure_one() | |||
|         next_date = fields.Datetime.from_string(self.start_date) | |||
|         while next_date <= start_date: | |||
|             next_date = self._get_next_term_date( | |||
|                 next_date, line.ordering_unit, line.ordering_interval) | |||
|         return next_date | |||
| 
 | |||
|     def generate_agreement_orders(self, start_date, end_date): | |||
|         """Method for generating agreement orders""" | |||
|         self.ensure_one() | |||
|         if not self.active: | |||
|             return | |||
|         lines_to_order = {} | |||
|         # Get next expiration date | |||
|         exp_date = fields.Datetime.from_string(self.next_expiration_date) | |||
|         if exp_date < end_date and self.prolong != 'unlimited': | |||
|             end_date = exp_date | |||
|         for line in self.agreement_line_ids: | |||
|             if not line.is_active: | |||
|                 continue | |||
|             # Get Date of Next Order | |||
|             next_order_date = self._get_next_order_date(line, start_date) | |||
|             while next_order_date <= end_date: | |||
|                 if not lines_to_order.get(next_order_date): | |||
|                     lines_to_order[next_order_date] = self.env[ | |||
|                         'recurring.agreement.line'] | |||
|                 lines_to_order[next_order_date] |= line | |||
|                 next_order_date = self._get_next_order_date( | |||
|                     line, next_order_date) | |||
|         dates = lines_to_order.keys() | |||
|         sorted(dates) | |||
|         for date in dates: | |||
|             order = self.order_ids.filtered( | |||
|                 lambda x: ( | |||
|                         fields.Date.to_string( | |||
|                             fields.Datetime.from_string(x.date_order)) == | |||
|                         fields.Date.to_string(date))) | |||
|             if not order: | |||
|                 self.create_order( | |||
|                     fields.Datetime.to_string(date), lines_to_order[date]) | |||
| 
 | |||
|     @api.model | |||
|     def generate_next_orders_planned(self, years=1, start_date=None): | |||
|         """Method for generating the planned orders""" | |||
|         if start_date: | |||
|             start_date = fields.Datetime.from_string(start_date) | |||
|         self.search([]).generate_next_orders( | |||
|             years=years, start_date=start_date) | |||
| 
 | |||
|     def action_generate_next_year_orders(self): | |||
|         """This will Generate Orders for Next year""" | |||
|         return self.generate_next_orders(years=1) | |||
| 
 | |||
|     def generate_next_orders(self, years=1, start_date=None): | |||
|         if not start_date: | |||
|             start_date = fields.Datetime.from_string(fields.Date.today()) | |||
|         end_date = start_date + relativedelta(years=years) | |||
|         for agreement in self: | |||
|             agreement.generate_agreement_orders(start_date, end_date) | |||
|         return True | |||
| 
 | |||
|     @api.model | |||
|     def confirm_current_orders_planned(self): | |||
|         """This will Confirm All Orders satisfying the Domain""" | |||
|         tomorrow = fields.Date.to_string( | |||
|             fields.Datetime.from_string(fields.Datetime.today()) + timedelta( | |||
|                 days=1)) | |||
|         orders = self.env['purchase.order'].search([ | |||
|             ('recurring_agreement_id', '!=', False), | |||
|             ('state', 'in', ('draft', 'sent')), | |||
|             ('date_order', '<', tomorrow) | |||
|         ]) | |||
|         for order in orders: | |||
|             order.signal_workflow('order_confirm') | |||
| 
 | |||
|     def unlink_orders(self, start_date): | |||
|         """ Remove the relation between ``self`` and the related record.""" | |||
|         orders = self.mapped('order_ids').filtered( | |||
|             lambda x: (x.state in ('draft', 'sent') and | |||
|                        x.date_order >= start_date)) | |||
|         orders.unlink() | |||
| 
 | |||
|     def action_generate_initial_order(self): | |||
|         """This will generate the Initial purchase Order from the Purchase | |||
|         Agreement""" | |||
|         self.ensure_one() | |||
|         agreement_lines = self.mapped('agreement_line_ids').filtered( | |||
|             'is_active') | |||
|         order = self.create_order(self.start_date, agreement_lines) | |||
|         self.write({'state': 'first'}) | |||
|         order.button_confirm() | |||
|         return { | |||
|             'domain': "[('id', '=', %s)]" % order.id, | |||
|             'view_type': 'form', | |||
|             'view_mode': 'form', | |||
|             'res_model': 'purchase.order', | |||
|             'context': self.env.context, | |||
|             'res_id': order.id, | |||
|             'view_id': [self.env.ref('purchase.purchase_order_form').id], | |||
|             'type': 'ir.actions.act_window', | |||
|             'nodestroy': True | |||
|         } | |||
| 
 | |||
|     def action_view_purchase_orders(self): | |||
|         """Returns All Orders Generated from the Agreement""" | |||
|         self.ensure_one() | |||
|         return { | |||
|             'type': 'ir.actions.act_window', | |||
|             'name': 'Orders', | |||
|             'views': [[False, 'tree'], [False, 'form']], | |||
|             'res_model': 'purchase.order', | |||
|             'domain': [('recurring_agreement_id', '=', self.id)], | |||
|             'context': "{'create': False}" | |||
|         } | |||
| @ -0,0 +1,73 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| from odoo import fields, models | |||
| from odoo.addons.base.models.decimal_precision import dp | |||
| 
 | |||
| 
 | |||
| class RecurringAgreementLine(models.Model): | |||
|     """Model generating purchase recurring agreement line""" | |||
|     _name = 'recurring.agreement.line' | |||
|     _description = 'Recurring Agreement Records' | |||
| 
 | |||
|     is_active = fields.Boolean(string='Active', default=True, | |||
|                                help='Unchecking this field, this quotation for' | |||
|                                     'this product is not generated') | |||
|     recurring_agreement_id = fields.Many2one('purchase.recurring.agreement', | |||
|                                              string='Agreement Reference', | |||
|                                              ondelete='cascade', | |||
|                                              help="The Corresponding purchase" | |||
|                                                   " order agreement") | |||
|     product_id = fields.Many2one('product.product', string='Product', | |||
|                                  ondelete='restrict', required=True) | |||
|     uom_id = fields.Many2one(related='product_id.product_tmpl_id.uom_id', | |||
|                              help="UOM of the product", string="Uom") | |||
|     additional_description = fields.Char(string='Description', size=30, | |||
|                                          help='Additional description that will' | |||
|                                               ' be added to the product ' | |||
|                                               'description on orders.') | |||
|     quantity = fields.Float(string='Quantity', required=True, | |||
|                             help='Quantity of the product', default=1.0) | |||
|     ordering_interval = fields.Integer(string='Interval', required=True, | |||
|                                        help="Interval in time units for making" | |||
|                                             " an order of this product", | |||
|                                        default=1) | |||
|     ordering_unit = fields.Selection([('days', 'Days'), ('weeks', 'Weeks'), | |||
|                                       ('months', 'Months'), ('years', 'Years')], | |||
|                                      string='Interval Unit', required=True, | |||
|                                      help="It indicated the recurring time unit" | |||
|                                      , default='months') | |||
|     last_order_date = fields.Datetime(help='Date of the last Purchase order ' | |||
|                                            'generated', string='Last Order') | |||
|     specific_price = fields.Float( | |||
|         string='Specific Price', | |||
|         digits_compute=dp.get_precision('Purchase Price'), | |||
|         help='Specific price for this product. Keep empty to use the list ' | |||
|              'price while generating order') | |||
|     list_price = fields.Float(related='product_id.list_price', readonly=True, | |||
|                               string="List Price", help='Unit price of product') | |||
| 
 | |||
|     _sql_constraints = [ | |||
|         ('line_qty_zero', 'CHECK (quantity > 0)', | |||
|          'All product quantities must be greater than 0.\n'), | |||
|         ('line_interval_zero', 'CHECK (ordering_interval > 0)', | |||
|          'All ordering intervals must be greater than 0.\n'), | |||
|     ] | |||
| @ -0,0 +1,38 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| from odoo import models | |||
| 
 | |||
| 
 | |||
| class ResPartner(models.Model): | |||
|     """ Inherited for adding new smart button purchase agreement""" | |||
|     _inherit = 'res.partner' | |||
| 
 | |||
|     def action_purchase_agreement(self): | |||
|         """Method of agreement smart button """ | |||
|         return { | |||
|             'name': 'agreements', | |||
|             'type': 'ir.actions.act_window', | |||
|             'res_model': 'purchase.recurring.agreement', | |||
|             'view_mode': 'tree,form', | |||
|             'view_id': False, | |||
|             'domain': [('partner_id', '=', self.id)] | |||
|         } | |||
| 
 | 
| After Width: | Height: | Size: 3.6 KiB | 
| After Width: | Height: | Size: 310 B | 
| After Width: | Height: | Size: 1.3 KiB | 
| After Width: | Height: | Size: 1.4 KiB | 
| After Width: | Height: | Size: 576 B | 
| After Width: | Height: | Size: 733 B | 
| After Width: | Height: | Size: 911 B | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 673 B | 
| After Width: | Height: | Size: 878 B | 
| After Width: | Height: | Size: 653 B | 
| After Width: | Height: | Size: 905 B | 
| After Width: | Height: | Size: 839 B | 
| After Width: | Height: | Size: 427 B | 
| After Width: | Height: | Size: 627 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 988 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 1.5 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.9 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 2.1 KiB | 
| After Width: | Height: | Size: 4.4 KiB | 
| After Width: | Height: | Size: 589 B | 
| After Width: | Height: | Size: 3.4 KiB | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 967 B | 
| After Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 3.8 KiB | 
| After Width: | Height: | Size: 5.0 KiB | 
| After Width: | Height: | Size: 51 KiB | 
| After Width: | Height: | Size: 56 KiB | 
| After Width: | Height: | Size: 51 KiB | 
| After Width: | Height: | Size: 70 KiB | 
| After Width: | Height: | Size: 59 KiB | 
| After Width: | Height: | Size: 54 KiB | 
| After Width: | Height: | Size: 39 KiB | 
| After Width: | Height: | Size: 299 KiB | 
| After Width: | Height: | Size: 118 KiB | 
| After Width: | Height: | Size: 128 KiB | 
| After Width: | Height: | Size: 178 KiB | 
| After Width: | Height: | Size: 166 KiB | 
| After Width: | Height: | Size: 129 KiB | 
| After Width: | Height: | Size: 160 KiB | 
| After Width: | Height: | Size: 158 KiB | 
| After Width: | Height: | Size: 185 KiB | 
| After Width: | Height: | Size: 157 KiB | 
| After Width: | Height: | Size: 157 KiB | 
| After Width: | Height: | Size: 157 KiB | 
| After Width: | Height: | Size: 272 KiB | 
| After Width: | Height: | Size: 155 KiB | 
| After Width: | Height: | Size: 440 KiB | 
| After Width: | Height: | Size: 80 KiB | 
| After Width: | Height: | Size: 7.7 KiB | 
| @ -0,0 +1,667 @@ | |||
| <div style="background-color: #714B67; min-height: 600px; width: 100%; padding: 15px; position: relative;"> | |||
|     <!-- TITLE BAR --> | |||
|     <div | |||
|             style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;"> | |||
|         <img src="assets/misc/cybrosys-logo.png" width="42" height="42" | |||
|              style="width: 42px; height: 42px;"/> | |||
|         <div> | |||
|             <div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" | |||
|                  class="mr-2"> | |||
|                 <i class="fa fa-check mr-1"></i>Community | |||
|             </div> | |||
|             <div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" | |||
|                  class="mr-2"> | |||
|                 <i class="fa fa-check mr-1"></i>Enterprise | |||
|             </div> | |||
|             <div style="color: #017E84; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" | |||
|                  class="mr-2"> | |||
|                 <i class="fa fa-check mr-1"></i>Odoo.sh | |||
|             </div> | |||
|         </div> | |||
|     </div> | |||
|     <!-- END OF TITLE BAR --> | |||
|     <!-- APP HERO --> | |||
|     <h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;"> | |||
|         Purchase Recurring Orders</h1> | |||
|     <p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;"> | |||
|         Helps To Create Recurring Orders For Purchases Based On The Information | |||
|         Provided</p> | |||
|     <!-- END OF APP HERO --> | |||
|     <img src="assets/screenshots/hero.gif" | |||
|          style="width: 75%; height: auto; position: absolute; margin-left: auto; margin-right: auto; top: 45%; left: 12%; right: auto;"/> | |||
| </div> | |||
| 
 | |||
| <!-- NAVIGATION SECTION --> | |||
| <div class="d-flex align-items-center" | |||
|      style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;"> | |||
|     <div class="d-flex justify-content-center align-items-center mr-2" | |||
|          style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> | |||
|         <img src="assets/misc/compass.png"/> | |||
|     </div> | |||
|     <h2 class="mt-2" | |||
|         style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> | |||
|         Explore This | |||
|         Module</h2> | |||
| </div> | |||
| <div class="row my-4" style="font-family: 'Montserrat', sans-serif;"> | |||
|     <div class="col-sm-12 col-md-6 my-3"> | |||
|         <a href="#overview"> | |||
|             <div class="d-flex justify-content-between align-items-center" | |||
|                  style="background-color: #f5f5f5; padding: 30px; width: 100%;"> | |||
|                 <div> | |||
|                     <span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span> | |||
|                     <span | |||
|                             style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33;  display: block;">Learn | |||
|                         more about this | |||
|                         module</span> | |||
|                 </div> | |||
|                 <img src="assets/misc/right-arrow.png" width="36" height="36"/> | |||
|             </div> | |||
|         </a> | |||
|     </div> | |||
|     <div class="col-sm-12 col-md-6 my-3"> | |||
|         <a href="#features"> | |||
|             <div class="d-flex justify-content-between align-items-center" | |||
|                  style="background-color: #f5f5f5; padding: 30px; width: 100%;"> | |||
|                 <div> | |||
|                     <span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span> | |||
|                     <span | |||
|                             style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33;  display: block;">View | |||
|                         features of this | |||
|                         module</span> | |||
|                 </div> | |||
|                 <img src="assets/misc/right-arrow.png" width="36" height="36"/> | |||
|             </div> | |||
|         </a> | |||
|     </div> | |||
|     <div class="col-sm-12 col-md-6 my-3"> | |||
|         <a href="#screenshots"> | |||
|             <div class="d-flex justify-content-between align-items-center" | |||
|                  style="background-color: #f5f5f5; padding: 30px; width: 100%;"> | |||
|                 <div> | |||
|                     <span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span> | |||
|                     <span | |||
|                             style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33;  display: block;">View | |||
|                         screenshots for this | |||
|                         module</span> | |||
|                 </div> | |||
|                 <img src="assets/misc/right-arrow.png" width="36" height="36"/> | |||
|             </div> | |||
|         </a> | |||
|     </div> | |||
| </div> | |||
| <!-- END OF NAVIGATION SECTION --> | |||
| 
 | |||
| <!-- OVERVIEW SECTION --> | |||
| <div class="d-flex align-items-center" | |||
|      style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview"> | |||
|     <div class="d-flex justify-content-center align-items-center mr-2" | |||
|          style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> | |||
|         <img src="assets/misc/pie-chart.png"/> | |||
|     </div> | |||
|     <h2 class="mt-2" | |||
|         style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> | |||
|         Overview | |||
|     </h2> | |||
| </div> | |||
| <div class="row" | |||
|      style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> | |||
|     <div class="col-sm-12 py-4"> | |||
|         This module is useful to create recurring orders for Purchases based | |||
|         on information(prolongation, Interval, etc.,) provided. | |||
| 
 | |||
|     </div> | |||
| </div> | |||
| <!-- END OF OVERVIEW SECTION --> | |||
| 
 | |||
| <!-- FEATURES SECTION --> | |||
| <div class="d-flex align-items-center" | |||
|      style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features"> | |||
|     <div class="d-flex justify-content-center align-items-center mr-2" | |||
|          style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> | |||
|         <img src="assets/misc/features.png"/> | |||
|     </div> | |||
|     <h2 class="mt-2" | |||
|         style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> | |||
|         Features | |||
|     </h2> | |||
| </div> | |||
| <div class="row" | |||
|      style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> | |||
|     <div class="col-sm-12 col-md-6"> | |||
|         <div class="d-flex align-items-center" | |||
|              style="margin-top: 40px; margin-bottom: 40px"> | |||
|             <img src="assets/misc/check-box.png" class="mr-2"/> | |||
|             <span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Creates recurring orders for purchase</span> | |||
|         </div> | |||
|         <div class="d-flex align-items-center" | |||
|              style="margin-top: 40px; margin-bottom: 40px"> | |||
|             <img src="assets/misc/check-box.png" class="mr-2"/> | |||
|             <span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Scheduled action for creating recurring orders</span> | |||
|         </div> | |||
| 
 | |||
|     </div> | |||
| </div> | |||
| <!-- END OF FEATURES SECTION --> | |||
| 
 | |||
| <!-- SCREENSHOTS SECTION --> | |||
| <div class="d-flex align-items-center" | |||
|      style="border-bottom: 2px solid #714B67; padding: 15px 0px;" | |||
|      id="screenshots"> | |||
|     <div class="d-flex justify-content-center align-items-center mr-2" | |||
|          style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> | |||
|         <img src="assets/misc/pictures.png"/> | |||
|     </div> | |||
|     <h2 class="mt-2" | |||
|         style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> | |||
|         Screenshots | |||
|     </h2> | |||
| </div> | |||
| <div class="row"> | |||
|     <div class="col-sm-12"> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Menu for viewing and creating Recurring Order Agreements</h3> | |||
| 
 | |||
|             <img src="assets/screenshots/1.png" class="img-thumbnail"/> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Create Recurring Order Agreement</h3> | |||
|             <p>Create new recurring order agreement by filling the details in | |||
|                 the form and add the products in Agreement Order Line.</p> | |||
|             <img src="assets/screenshots/2.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Generate Initial Order</h3> | |||
|             <p>Click on the Generate Initial Order button for generating the | |||
|                 first order.</p> | |||
| 
 | |||
|             <img src="assets/screenshots/3.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Initial order generated</h3> | |||
|             <p> | |||
|                 First Purchase Order Generated according to the details added in | |||
|                 the Recurring purchase agreement. | |||
|             </p> | |||
|             <img src="assets/screenshots/4.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Smart button for Orders</h3> | |||
|             <p> | |||
|                 We can see all orders created from the recurring purchase | |||
|                 agreement from the smart button which shows the number of | |||
|                 orders. | |||
|             </p> | |||
|             <img src="assets/screenshots/5.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Generate Next year Orders</h3> | |||
|             <p> | |||
|                 It is possible to create next year orders at one click. | |||
|             </p> | |||
|             <img src="assets/screenshots/6.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Number of Orders increased | |||
|             </h3> | |||
|             <img src="assets/screenshots/7.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Generated Orders</h3> | |||
|             <p> | |||
|                 All orders generated including Initial and Next year Orders. | |||
|             </p> | |||
|             <img src="assets/screenshots/8.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Renew Agreement</h3> | |||
|             <img src="assets/screenshots/9.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Update the Comments for Agreement Renewal </h3> | |||
| 
 | |||
|             <img src="assets/screenshots/10.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Fixed Term Purchase Recurring Agreement </h3> | |||
|             <p> | |||
|                 Enter the start and end date of fixed term agreement. | |||
|             </p> | |||
| 
 | |||
|             <img src="assets/screenshots/16.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Scheduled Action for generating Recurring Orders for Next | |||
|                 Year</h3> | |||
|             <img src="assets/screenshots/11.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Generate Agreement button in Purchase Order</h3> | |||
|             <img src="assets/screenshots/12.png" class="img-thumbnail"> | |||
|         </div> | |||
|         <div style="display: block; margin: 30px auto;"> | |||
|             <h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> | |||
|                 Current Purchase Order set as new Purchase Agreement.</h3> | |||
|             <img src="assets/screenshots/13.png" class="img-thumbnail"> | |||
|         </div> | |||
|     </div> | |||
| </div> | |||
| <!-- END OF SCREENSHOTS SECTION --> | |||
| 
 | |||
| <!-- RELATED PRODUCTS --> | |||
| <div class="d-flex align-items-center" | |||
|      style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> | |||
|     <div class="d-flex justify-content-center align-items-center mr-2" | |||
|          style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> | |||
|         <img src="assets/misc/categories.png"/> | |||
|     </div> | |||
|     <h2 class="mt-2" | |||
|         style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> | |||
|         Related | |||
|         Products | |||
|     </h2> | |||
| </div> | |||
| <div class="row"> | |||
|     <div class="col-lg-12 d-flex flex-column justify-content-center" | |||
|          style="text-align: center; padding: 2.5rem 1rem !important;"> | |||
|         <h2 style="color: #212529 !important;">Suggested | |||
|             Products</h2> | |||
|         <hr | |||
|                 style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> | |||
| 
 | |||
|         <div id="demo1" class="row carousel slide" | |||
|              data-ride="carousel"> | |||
|             <!-- The slideshow --> | |||
|             <div class="carousel-inner"> | |||
|                 <div class="carousel-item active" | |||
|                      style="min-height:0px"> | |||
|                     <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | |||
|                          style="float:left"> | |||
|                         <a href="https://apps.odoo.com/apps/modules/14.0/product_brand_purchase/" | |||
|                            target="_blank"> | |||
|                             <div style="border-radius:10px"> | |||
|                                 <img class="img img-responsive center-block" | |||
|                                      style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                                      src="./assets/modules/product_brand.png"> | |||
|                             </div> | |||
|                         </a> | |||
|                     </div> | |||
|                     <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | |||
|                          style="float:left"> | |||
|                         <a href="https://apps.odoo.com/apps/modules/14.0/no_automatic_subscription/" | |||
|                            target="_blank"> | |||
|                             <div style="border-radius:10px"> | |||
|                                 <img class="img img-responsive center-block" | |||
|                                      style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                                      src="./assets/modules/automatic_subscription.png"> | |||
|                             </div> | |||
|                         </a> | |||
|                     </div> | |||
|                     <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | |||
|                          style="float:left"> | |||
|                         <a href="https://apps.odoo.com/apps/modules/14.0/follower_restrict/" | |||
|                            target="_blank"> | |||
|                             <div style="border-radius:10px"> | |||
|                                 <img class="img img-responsive center-block" | |||
|                                      style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                                      src="./assets/modules/follower_restrict.png"> | |||
|                             </div> | |||
|                         </a> | |||
|                     </div> | |||
|                 </div> | |||
|                 <div class="carousel-item" style="min-height:0px"> | |||
|                     <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | |||
|                          style="float:left"> | |||
|                         <a href="https://apps.odoo.com/apps/modules/14.0/mrp_work_order_print/" | |||
|                            target="_blank"> | |||
|                             <div style="border-radius:10px"> | |||
|                                 <img class="img img-responsive center-block" | |||
|                                      style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                                      src="./assets/modules/print_image.png"> | |||
|                             </div> | |||
|                         </a> | |||
|                     </div> | |||
|                     <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | |||
|                          style="float:left"> | |||
|                         <a href="https://apps.odoo.com/apps/modules/14.0/product_import/" | |||
|                            target="_blank"> | |||
|                             <div style="border-radius:10px"> | |||
|                                 <img class="img img-responsive center-block" | |||
|                                      style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                                      src="./assets/modules/product_url.png"> | |||
|                             </div> | |||
|                         </a> | |||
|                     </div> | |||
|                     <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | |||
|                          style="float:left"> | |||
|                         <a href="https://apps.odoo.com/apps/modules/14.0/sale_purchase_previous_product_cost/" | |||
|                            target="_blank"> | |||
|                             <div style="border-radius:10px"> | |||
|                                 <img class="img img-responsive center-block" | |||
|                                      style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                                      src="./assets/modules/multiple_reference.png"> | |||
|                             </div> | |||
|                         </a> | |||
|                     </div> | |||
|                 </div> | |||
|             </div> | |||
|             <!-- Left and right controls --> | |||
|             <a class="carousel-control-prev" href="#demo1" | |||
|                data-slide="prev" | |||
|                style="left:-25px;width: 35px;color: #000;"> <span | |||
|                     class="carousel-control-prev-icon"><i | |||
|                     class="fa fa-chevron-left" | |||
|                     style="font-size:24px"></i></span> </a> <a | |||
|                 class="carousel-control-next" href="#demo1" | |||
|                 data-slide="next" | |||
|                 style="right:-25px;width: 35px;color: #000;"> | |||
|                     <span class="carousel-control-next-icon"><i | |||
|                             class="fa fa-chevron-right" | |||
|                             style="font-size:24px"></i></span> | |||
|         </a> | |||
|         </div> | |||
|     </div> | |||
| </div> | |||
| <!-- END OF RELATED PRODUCTS --> | |||
| 
 | |||
| <!-- OUR SERVICES --> | |||
| <div class="d-flex align-items-center" | |||
|      style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> | |||
|     <div class="d-flex justify-content-center align-items-center mr-2" | |||
|          style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> | |||
|         <img src="assets/misc/star.png"/> | |||
|     </div> | |||
|     <h2 class="mt-2" | |||
|         style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> | |||
|         Our Services | |||
|     </h2> | |||
| </div> | |||
| <div class="container my-5"> | |||
|     <div class="row"> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/cogs.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Odoo Customization</h6> | |||
|         </div> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/wrench.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Odoo Implementation</h6> | |||
|         </div> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/lifebuoy.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Odoo Support</h6> | |||
|         </div> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/user.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Hire Odoo | |||
|                 Developer</h6> | |||
|         </div> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #54a0ff  !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/puzzle.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Odoo Integration</h6> | |||
|         </div> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/update.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Odoo Migration</h6> | |||
|         </div> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/consultation.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Odoo Consultancy</h6> | |||
|         </div> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/training.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Odoo Implementation</h6> | |||
|         </div> | |||
|         <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | |||
|             <div class="d-flex justify-content-center align-items-center mx-3 my-3" | |||
|                  style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | |||
|                 <img src="assets/icons/license.png" class="img-responsive" | |||
|                      height="48px" width="48px"> | |||
|             </div> | |||
|             <h6 class="text-center" | |||
|                 style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | |||
|                 Odoo Licensing Consultancy</h6> | |||
|         </div> | |||
|     </div> | |||
| </div> | |||
| <!--END OF OUR SERVICES --> | |||
| 
 | |||
| <!-- OUR INDUSTRIES --> | |||
| <div class="d-flex align-items-center" | |||
|      style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> | |||
|     <div class="d-flex justify-content-center align-items-center mr-2" | |||
|          style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> | |||
|         <img src="assets/misc/corporate.png"/> | |||
|     </div> | |||
|     <h2 class="mt-2" | |||
|         style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> | |||
|         Our | |||
|         Industries | |||
|     </h2> | |||
| </div> | |||
| <div class="container my-5"> | |||
|     <div class="row"> | |||
|         <div class="col-lg-3"> | |||
|             <div class="my-4 d-flex flex-column justify-content-center" | |||
|                  style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> | |||
|                 <img src="assets/icons/trading-black.png" | |||
|                      class="img-responsive mb-3" height="48px" width="48px"> | |||
|                 <h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | |||
|                     Trading | |||
|                 </h5> | |||
|                 <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | |||
|                     Easily procure | |||
|                     and sell your products</p> | |||
|             </div> | |||
|         </div> | |||
|         <div class="col-lg-3"> | |||
|             <div class="my-4 d-flex flex-column justify-content-center" | |||
|                  style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> | |||
|                 <img src="assets/icons/pos-black.png" | |||
|                      class="img-responsive mb-3" height="48px" width="48px"> | |||
|                 <h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | |||
|                     POS | |||
|                 </h5> | |||
|                 <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | |||
|                     Easy configuration | |||
|                     and convivial experience</p> | |||
|             </div> | |||
|         </div> | |||
|         <div class="col-lg-3"> | |||
|             <div class="my-4 d-flex flex-column justify-content-center" | |||
|                  style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> | |||
|                 <img src="assets/icons/education-black.png" | |||
|                      class="img-responsive mb-3" height="48px" width="48px"> | |||
|                 <h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | |||
|                     Education | |||
|                 </h5> | |||
|                 <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | |||
|                     A platform for educational management</p> | |||
|             </div> | |||
|         </div> | |||
|         <div class="col-lg-3"> | |||
|             <div class="my-4 d-flex flex-column justify-content-center" | |||
|                  style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> | |||
|                 <img src="assets/icons/manufacturing-black.png" | |||
|                      class="img-responsive mb-3" height="48px" | |||
|                      width="48px"> | |||
|                 <h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | |||
|                     Manufacturing | |||
|                 </h5> | |||
|                 <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | |||
|                     Plan, track and schedule your operations</p> | |||
|             </div> | |||
|         </div> | |||
|         <div class="col-lg-3"> | |||
|             <div class="my-4 d-flex flex-column justify-content-center" | |||
|                  style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> | |||
|                 <img src="assets/icons/ecom-black.png" | |||
|                      class="img-responsive mb-3" height="48px" width="48px"> | |||
|                 <h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | |||
|                     E-commerce & Website | |||
|                 </h5> | |||
|                 <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | |||
|                     Mobile friendly, | |||
|                     awe-inspiring product pages</p> | |||
|             </div> | |||
|         </div> | |||
|         <div class="col-lg-3"> | |||
|             <div class="my-4 d-flex flex-column justify-content-center" | |||
|                  style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> | |||
|                 <img src="assets/icons/service-black.png" | |||
|                      class="img-responsive mb-3" height="48px" width="48px"> | |||
|                 <h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | |||
|                     Service Management | |||
|                 </h5> | |||
|                 <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | |||
|                     Keep track of services and invoice</p> | |||
|             </div> | |||
|         </div> | |||
|         <div class="col-lg-3"> | |||
|             <div class="my-4 d-flex flex-column justify-content-center" | |||
|                  style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> | |||
|                 <img src="assets/icons/restaurant-black.png" | |||
|                      class="img-responsive mb-3" height="48px" width="48px"> | |||
|                 <h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | |||
|                     Restaurant | |||
|                 </h5> | |||
|                 <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | |||
|                     Run your bar or restaurant methodically</p> | |||
|             </div> | |||
|         </div> | |||
|         <div class="col-lg-3"> | |||
|             <div class="my-4 d-flex flex-column justify-content-center" | |||
|                  style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> | |||
|                 <img src="assets/icons/hotel-black.png" | |||
|                      class="img-responsive mb-3" height="48px" width="48px"> | |||
|                 <h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | |||
|                     Hotel Management | |||
|                 </h5> | |||
|                 <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | |||
|                     An all-inclusive | |||
|                     hotel management application</p> | |||
|             </div> | |||
|         </div> | |||
|     </div> | |||
| </div> | |||
| <!--  END OF OUR INDUSTRIES --> | |||
| 
 | |||
| <!-- SUPPORT --> | |||
| <div class="d-flex align-items-center" | |||
|      style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> | |||
|     <div class="d-flex justify-content-center align-items-center mr-2" | |||
|          style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> | |||
|         <img src="assets/misc/customer-support.png"/> | |||
|     </div> | |||
|     <h2 class="mt-2" | |||
|         style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> | |||
|         Support | |||
|     </h2> | |||
| </div> | |||
| <div class="container mt-5"> | |||
|     <div class="row"> | |||
|         <div class="col-sm-12 col-md-6"> | |||
|             <div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;"> | |||
|                 <div class="mr-4" | |||
|                      style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;"> | |||
|                     <img src="assets/misc/support.png" height="48" width="48" | |||
|                          style="width: 42px; height: 42px;"/> | |||
|                 </div> | |||
|                 <div> | |||
|                     <h4>Need Help?</h4> | |||
|                     <p style="line-height: 100%;">Got questions or need help? | |||
|                         Get in touch.</p> | |||
|                     <a href="mailto:odoo@cybrosys.com"> | |||
|                         <p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;"> | |||
|                             odoo@cybrosys.com</p> | |||
|                     </a> | |||
|                 </div> | |||
|             </div> | |||
|         </div> | |||
|         <div class="col-sm-12 col-md-6"> | |||
|             <div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;"> | |||
|                 <div class="mr-4" | |||
|                      style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;"> | |||
|                     <img src="assets/misc/whatsapp.png" height="52" width="52" | |||
|                          style="width: 52px; height: 52px;"/> | |||
|                 </div> | |||
|                 <div> | |||
|                     <h4>WhatsApp</h4> | |||
|                     <p style="line-height: 100%;">Say hi to us on WhatsApp!</p> | |||
|                     <a href="https://api.whatsapp.com/send?phone=918606827707"> | |||
|                         <p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;"> | |||
|                             +91 86068 | |||
|                             27707</p> | |||
|                     </a> | |||
|                 </div> | |||
|             </div> | |||
|         </div> | |||
|     </div> | |||
|     <div class="row"> | |||
|         <div class="col-sm-12 my-5 d-flex justify-content-center align-items-center"> | |||
|             <img src="assets/misc/logo.png" width="144" height="31" | |||
|                  style="width:144px; height: 31px; margin-top: 40px;"/> | |||
|         </div> | |||
|     </div> | |||
| </div> | |||
| <!-- END OF SUPPORT --> | |||
| @ -0,0 +1,31 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <odoo> | |||
|     <!--Generate Agreement Button in Purchase Order --> | |||
|     <record id="purchase_order_form" model="ir.ui.view"> | |||
|         <field name="name"> | |||
|             purchase.order.view.form.inherit.purchase.recurring.orders | |||
|         </field> | |||
|         <field name="model">purchase.order</field> | |||
|         <field name="inherit_id" ref="purchase.purchase_order_form"/> | |||
|         <field name="arch" type="xml"> | |||
|             <button name="button_cancel" position="after"> | |||
|                 <button name="action_generate_agreement" | |||
|                         string="Generate agreement" type="object"/> | |||
|             </button> | |||
|         </field> | |||
|     </record> | |||
|     <record id="view_purchase_order_filter" model="ir.ui.view"> | |||
|         <field name="name"> | |||
|             purchase.order.view.list.inherit.purchase.recurring.orders | |||
|         </field> | |||
|         <field name="model">purchase.order</field> | |||
|         <field name="inherit_id" ref="purchase.view_purchase_order_filter"/> | |||
|         <field name="arch" type="xml"> | |||
|             <field name="name" position="after"> | |||
|                 <filter string="Not from agreements" name="is_agreement" | |||
|                         domain="[('is_agreement','=',False)]"/> | |||
|                 <separator/> | |||
|             </field> | |||
|         </field> | |||
|     </record> | |||
| </odoo> | |||
| @ -0,0 +1,172 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <odoo> | |||
|     <!--    Purchase Recurring Agreement tree View--> | |||
|     <record id="purchase_recurring_agreement_view_tree" model="ir.ui.view"> | |||
|         <field name="name">purchase.recurring.agreement.view.tree</field> | |||
|         <field name="model">purchase.recurring.agreement</field> | |||
|         <field name="type">tree</field> | |||
|         <field name="priority" eval="6"/> | |||
|         <field name="arch" type="xml"> | |||
|             <tree string="Recurring Orders Agreements"> | |||
|                 <field name="name"/> | |||
|                 <field name="partner_id"/> | |||
|                 <field name="start_date"/> | |||
|                 <field name="prolong"/> | |||
|                 <field name="next_expiration_date"/> | |||
|                 <field name="company_id" groups="base.group_multi_company"/> | |||
|             </tree> | |||
|         </field> | |||
|     </record> | |||
|     <!--    Purchase Recurring Agreement Form View--> | |||
|     <record id="purchase_recurring_agreement_view_form" model="ir.ui.view"> | |||
|         <field name="name">purchase.recurring.agreement.view.form</field> | |||
|         <field name="model">purchase.recurring.agreement</field> | |||
|         <field name="priority">6</field> | |||
|         <field name="arch" type="xml"> | |||
|             <form> | |||
|                 <header> | |||
|                     <button name="action_generate_initial_order" | |||
|                             class="oe_highlight" | |||
|                             states="empty" | |||
|                             string="Generate Initial Order" | |||
|                             type="object"/> | |||
|                     <button name="action_generate_next_year_orders" | |||
|                             string="Generate Next Year Orders" type="object" | |||
|                             icon="fa-envelope"/> | |||
|                     <button name="%(agreement_renewal_action)d" | |||
|                             type="action" | |||
|                             string="Renew Agreement" | |||
|                             attrs="{'invisible': [('prolong','!=', 'recurrent')]}"/> | |||
|                 </header> | |||
|                 <sheet> | |||
|                     <div name="button_box" class="oe_button_box"> | |||
|                         <button class="oe_stat_button" type="object" | |||
|                                 name="action_view_purchase_orders" | |||
|                                 attrs="{'invisible' : [('order_count','=',0)]}" | |||
|                                 icon="fa-file"> | |||
|                             <field string="Orders" name="order_count" | |||
|                                    widget="statinfo"/> | |||
|                         </button> | |||
|                     </div> | |||
|                     <div class="oe_title"> | |||
|                         <h1> | |||
|                             <field name="name"/> | |||
|                         </h1> | |||
|                     </div> | |||
|                     <group> | |||
|                         <group> | |||
|                             <field name="partner_id"/> | |||
|                             <field name="company_id" | |||
|                                    groups="base.group_multi_company"/> | |||
|                             <field name="prolong" | |||
|                                    attrs="{'readonly':[('renewal_state','!=','not_renewed')]}"/> | |||
| 
 | |||
|                             <field name="last_renovation_date" readonly="1" | |||
|                                    attrs="{'invisible': [('prolong','!=', 'recurrent')]}"/> | |||
|                             <field name="state" invisible="1"/> | |||
|                             <field name="renewal_state" invisible="1"/> | |||
|                         </group> | |||
|                         <group> | |||
|                             <field name="active" invisible="1"/> | |||
|                             <field name="name" invisible="1"/> | |||
|                             <field name="start_date" | |||
|                                    attrs="{'readonly':[('state','!=','empty')]}"/> | |||
|                             <field name="next_expiration_date"/> | |||
|                             <field name="prolong_unit" | |||
|                                    attrs="{'required': [('prolong', '!=', 'fixed')]}"/> | |||
|                         </group> | |||
|                         <group> | |||
|                             <group> | |||
|                                 <group attrs="{'invisible': [('prolong','=', 'fixed')]}" | |||
|                                        colspan="4" col="4"> | |||
|                                     <field name="prolong_interval" | |||
|                                            attrs="{'required': [('prolong', '!=', 'fixed')]}"/> | |||
|                                 </group> | |||
|                                 <group attrs="{'invisible': [('prolong','!=', 'fixed')]}" | |||
|                                        colspan="4" col="2"> | |||
|                                     <field name="end_date" | |||
|                                            attrs="{'required': [('prolong', '=', 'fixed')]}"/> | |||
|                                 </group> | |||
|                             </group> | |||
|                         </group> | |||
|                     </group> | |||
|                     <notebook colspan="4"> | |||
|                         <page string="Lines"> | |||
|                             <field name="agreement_line_ids"> | |||
|                                 <tree string="Agreement lines" | |||
|                                       editable="bottom"> | |||
|                                     <field name="is_active" optional="hide"/> | |||
|                                     <field name="product_id"/> | |||
|                                     <field name="additional_description"/> | |||
|                                     <field name="quantity"/> | |||
|                                     <field name="uom_id"/> | |||
|                                     <field name="list_price"/> | |||
|                                     <field name="specific_price"/> | |||
|                                     <field name="ordering_interval"/> | |||
|                                     <field name="ordering_unit"/> | |||
|                                     <field name="last_order_date" | |||
|                                            readonly="True"/> | |||
|                                 </tree> | |||
|                             </field> | |||
|                         </page> | |||
|                         <page string="Renewals" | |||
|                               attrs="{'invisible': [('prolong','!=', 'recurrent')]}"> | |||
|                             <field colspan="4" mode="tree" name="renewal_ids" | |||
|                                    widget="one2many_list" nolabel="1"> | |||
|                                 <tree string="Agreement Renewals"> | |||
|                                     <field name="date"/> | |||
|                                     <field name="comments"/> | |||
|                                 </tree> | |||
|                             </field> | |||
|                         </page> | |||
|                     </notebook> | |||
|                     <div class="oe_clear"/> | |||
|                     <field name="notes"/> | |||
|                 </sheet> | |||
|                 <div class="oe_chatter"> | |||
|                     <field name="message_follower_ids" widget="mail_followers" | |||
|                            groups="base.group_user"/> | |||
|                     <field name="message_ids" widget="mail_thread" | |||
|                            placeholder="Share a message..."/> | |||
|                 </div> | |||
|             </form> | |||
|         </field> | |||
|     </record> | |||
|     <!--    Purchase Recurring Agreement search View--> | |||
|     <record id="purchases_recurring_agreement_view_search" model="ir.ui.view"> | |||
|         <field name="name">purchase.recurring.agreement.view.search</field> | |||
|         <field name="model">purchase.recurring.agreement</field> | |||
|         <field name="arch" type="xml"> | |||
|             <search> | |||
|                 <field name="name" | |||
|                        filter_domain="[('name', 'ilike', self)]"/> | |||
|                 <field name="partner_id" | |||
|                        filter_domain="[('partner_id', 'child_of', self)]"/> | |||
|             </search> | |||
|         </field> | |||
|     </record> | |||
|     <!--  Recurring Orders Agreement Menu Action--> | |||
|     <record id="action_recurring_orders_agreement" | |||
|             model="ir.actions.act_window"> | |||
|         <field name="name">Recurring Order Agreement</field> | |||
|         <field name="res_model">purchase.recurring.agreement</field> | |||
|         <field name="view_mode">tree,form</field> | |||
|         <field name="help" type="html"> | |||
|             <p class="oe_view_nocontent_create"> | |||
|                 Click to set a new agreement. | |||
|             </p> | |||
|             <p> | |||
|                 Agreements are the way you define the commercial relation with | |||
|                 your customers which specify certain | |||
|                 products/services that you are providing them which requires a | |||
|                 recurring order. | |||
|             </p> | |||
|         </field> | |||
|     </record> | |||
|     <!--   Menu Recurring Order Agreement--> | |||
|     <menuitem name="Recurring Order Agreement" | |||
|               id="menu_recurring_order_agreement" | |||
|               parent="purchase.menu_procurement_management" | |||
|               action="action_recurring_orders_agreement" | |||
|               sequence="4"/> | |||
| </odoo> | |||
| @ -0,0 +1,21 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <odoo> | |||
|     <!--      Agreement Smart Button--> | |||
|     <record id="view_partner_form" model="ir.ui.view"> | |||
|         <field name="name"> | |||
|             res.partner.view.form.inherit.purchase.recurring.orders | |||
|         </field> | |||
|         <field name="model">res.partner</field> | |||
|         <field name="inherit_id" ref="base.view_partner_form"/> | |||
|         <field name="priority" eval="20"/> | |||
|         <field name="arch" type="xml"> | |||
|             <xpath expr="//div[@name='button_box']" position="inside"> | |||
|                 <button name="action_purchase_agreement" | |||
|                         type="object" | |||
|                         class="oe_stat_button" | |||
|                         icon="fa-file-text-o" | |||
|                         string="Agreements"/> | |||
|             </xpath> | |||
|         </field> | |||
|     </record> | |||
| </odoo> | |||
| @ -0,0 +1,22 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ############################################################################### | |||
| from . import agreement_renewal | |||
| @ -0,0 +1,54 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ################################################################################ | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |||
| #    Author: Ruksana P (odoo@cybrosys.com) | |||
| # | |||
| #    You can modify it under the terms of the GNU AFFERO | |||
| #    GENERAL PUBLIC LICENSE (AGPL v3), Version 3. | |||
| # | |||
| #    This program is distributed in the hope that it will be useful, | |||
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |||
| #    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
| #    (AGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ################################################################################ | |||
| from odoo import fields, models | |||
| 
 | |||
| 
 | |||
| class AgreementRenewal(models.TransientModel): | |||
|     """ New wizard for creating new renewal for agreement """ | |||
|     _name = "agreement.renewal" | |||
|     _description = "Agreement Renewal Form" | |||
| 
 | |||
|     def _default_date(self): | |||
|         """Method for getting the renewal date""" | |||
|         agreements = self.env['purchase.recurring.agreement'].browse( | |||
|             self.env.context.get('active_ids', [])) | |||
|         return agreements[:1].next_expiration_date | |||
| 
 | |||
|     date = fields.Date(string='Renewal Date', required=True, | |||
|                        default=_default_date, | |||
|                        help="Effective date of the renewal. This date is the " | |||
|                             "one taken into account in the next renewal") | |||
|     comments = fields.Char(string='Comments', size=200, help='Renewal comments') | |||
| 
 | |||
|     def action_renewal(self): | |||
|         """Method for renewal of purchase recurring agreement""" | |||
|         self.ensure_one() | |||
|         agreement_ids = self.env.context.get('active_ids', []) | |||
|         for agreement_id in agreement_ids: | |||
|             self.env['agreement.renewal.line'].create( | |||
|                 {'recurring_agreement_id': agreement_id, | |||
|                  'date': self.date, | |||
|                  'comments': self.comments}) | |||
|         self.env['purchase.recurring.agreement'].browse(agreement_ids).write( | |||
|             {'last_renovation_date': self.date, | |||
|              'renewal_state': 'renewed'}) | |||
|         return True | |||
| @ -0,0 +1,38 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <odoo> | |||
|     <!-- Purchase Agreement Renewal Wizard Form View --> | |||
|     <record id="agreement_renewal_view_form" model="ir.ui.view"> | |||
|         <field name="name">agreement.renewal.view.form</field> | |||
|         <field name="model">agreement.renewal</field> | |||
|         <field name="arch" type="xml"> | |||
|             <form> | |||
|                 <sheet> | |||
|                     <group> | |||
|                         <group> | |||
|                             <field name="date"/> | |||
|                             <separator string="" colspan="4"/> | |||
|                             <field name="comments" default_focus="1"/> | |||
|                             <separator string="" colspan="4"/> | |||
|                         </group> | |||
|                     </group> | |||
|                 </sheet> | |||
|                 <footer> | |||
|                     <button special="cancel" class="oe_highlight" | |||
|                             string="Cancel" icon="fa-close"/> | |||
|                     <button name="action_renewal" class="oe_highlight" | |||
|                             string="Renew Agreement" type="object" | |||
|                             icon="fa-refresh"/> | |||
|                 </footer> | |||
|             </form> | |||
|         </field> | |||
|     </record> | |||
|     <!-- Purchase Agreement Renewal Wizard Action --> | |||
|     <record id="agreement_renewal_action" model="ir.actions.act_window"> | |||
|         <field name="type">ir.actions.act_window</field> | |||
|         <field name="name">Renew Agreement</field> | |||
|         <field name="res_model">agreement.renewal</field> | |||
|         <field name="view_mode">form</field> | |||
|         <field name="view_id" ref="agreement_renewal_view_form"/> | |||
|         <field name="target">new</field> | |||
|     </record> | |||
| </odoo> | |||