diff --git a/subscription_package/README.md b/subscription_package/README.md new file mode 100644 index 000000000..25d1f9f97 --- /dev/null +++ b/subscription_package/README.md @@ -0,0 +1,36 @@ +Subscription Package for Community +================================== +* Subscription Package for Odoo 15 community edition + +Installation +============ + - www.odoo.com/documentation/15.0/setup/install.html + - Install our custom addon + +Company +------- +* 'Cybrosys Techno Solutions `__ + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +Credits +-------- +* Developer: Amal Prasad @ Cybrosys, + Alakananda @ Cybrosys + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com + +Further information +=================== +HTML Description: ``__ \ No newline at end of file diff --git a/subscription_package/__init__.py b/subscription_package/__init__.py new file mode 100644 index 000000000..f8545aae7 --- /dev/null +++ b/subscription_package/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from . import models +from . import report +from . import wizard diff --git a/subscription_package/__manifest__.py b/subscription_package/__manifest__.py new file mode 100644 index 000000000..ac6d79e03 --- /dev/null +++ b/subscription_package/__manifest__.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2022-TODAY Cybrosys Technologies (). +# Author: Cybrosys Techno Solutions () +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### + +{ + 'name': 'Subscription Management For Community', + 'Version': '15.0.1.0.0', + 'summary': 'Subscription Package Management Module For Odoo15 Community', + 'description': 'Subscription Package Management Module For Odoo15 Community', + 'category': 'Sales', + 'author': 'Cybrosys Techno solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'sale_management'], + 'data': [ + 'security/security.xml', + 'security/ir.model.access.csv', + 'data/uom_demo.xml', + 'data/subscription_stage_data.xml', + 'data/mail_template.xml', + 'data/cron.xml', + 'wizard/subscription_close_wizard.xml', + 'views/subscription_package.xml', + 'views/subscription_products.xml', + 'views/subscription_plan.xml', + 'views/subscription_stage.xml', + 'views/subscription_close.xml', + 'views/subscription_renew.xml', + 'views/mail_activity_views.xml', + 'views/res_partner.xml', + 'report/subscription_report_view.xml', + ], + 'images': ['static/description/banner.png'], + 'license': 'AGPL-3', + 'installable': True, + 'application': True, + 'auto_install': False, +} diff --git a/subscription_package/data/cron.xml b/subscription_package/data/cron.xml new file mode 100644 index 000000000..d5459a16b --- /dev/null +++ b/subscription_package/data/cron.xml @@ -0,0 +1,14 @@ + + + + + Check Close Limit + + code + model.close_limit_cron() + 1 + days + -1 + + + \ No newline at end of file diff --git a/subscription_package/data/mail_template.xml b/subscription_package/data/mail_template.xml new file mode 100644 index 000000000..61a4ff74f --- /dev/null +++ b/subscription_package/data/mail_template.xml @@ -0,0 +1,56 @@ + + + + + Subscription: Email Renew Alert + + {{ object.company_id.name }}: Please check the subscription {{ object.name }} + {{ object.company_id.email }} + {{ object.partner_id.email }} + + {{ object.partner_id.lang }} + +
+ + + + + + + +
+ + + + + Subscription Renew Alert +
+ + + + + + + + +
+

Dear, +

+

Your subscription Plan + + is going to Expired on + . +

+

If you have some concerns about it, please contact your contact person + + or reply to this email. +

+

Kind regards.

+
+
+
+
+ +
\ No newline at end of file diff --git a/subscription_package/data/subscription_stage_data.xml b/subscription_package/data/subscription_stage_data.xml new file mode 100644 index 000000000..ee7425778 --- /dev/null +++ b/subscription_package/data/subscription_stage_data.xml @@ -0,0 +1,25 @@ + + + + + + Draft + 5 + draft + + + + In Progress + 10 + progress + + + + Closed + 15 + + closed + + + + \ No newline at end of file diff --git a/subscription_package/data/uom_demo.xml b/subscription_package/data/uom_demo.xml new file mode 100644 index 000000000..23ca52f94 --- /dev/null +++ b/subscription_package/data/uom_demo.xml @@ -0,0 +1,24 @@ + + + + + + Time + + + + + Months + + reference + + + + + Years + + bigger + + + + \ No newline at end of file diff --git a/subscription_package/models/__init__.py b/subscription_package/models/__init__.py new file mode 100644 index 000000000..eaa606d7f --- /dev/null +++ b/subscription_package/models/__init__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from . import subscription_plan +from . import subscription_stage +from . import subscription_package +from . import subscription_products +from . import subscription_close +from . import subscription_renew +from . import res_partner diff --git a/subscription_package/models/res_partner.py b/subscription_package/models/res_partner.py new file mode 100644 index 000000000..171c7f58d --- /dev/null +++ b/subscription_package/models/res_partner.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import fields, models + + +class Partner(models.Model): + _inherit = 'res.partner' + + active_subscription = fields.Boolean(string="Active Subscription", + default=False) + subscription_product_line_ids = fields.One2many('subscription.package.product.line', + 'res_partner_id', + ondelete='restrict', + string='Products Line') diff --git a/subscription_package/models/subscription_close.py b/subscription_package/models/subscription_close.py new file mode 100644 index 000000000..a5c2fa31f --- /dev/null +++ b/subscription_package/models/subscription_close.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import models, fields + + +class SubscriptionPackageStopReason(models.Model): + _name = "subscription.package.stop" + _description = "Subscription Package Stop Reason" + _order = 'sequence' + + sequence = fields.Integer(help="Determine the display order", index=True, + string='Sequence') + name = fields.Char(string='Reason', required=True) diff --git a/subscription_package/models/subscription_package.py b/subscription_package/models/subscription_package.py new file mode 100644 index 000000000..17c33f319 --- /dev/null +++ b/subscription_package/models/subscription_package.py @@ -0,0 +1,386 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import _, api, models, fields, SUPERUSER_ID +import datetime +from odoo.exceptions import UserError +from dateutil.relativedelta import relativedelta + + +class SubscriptionPackageProductLine(models.Model): + _name = 'subscription.package.product.line' + _description = 'Subscription Product Lines' + + subscription_id = fields.Many2one('subscription.package', store=True, + string='Subscription') + company_id = fields.Many2one('res.company', string='Company', store=True, + related='subscription_id.company_id') + create_date = fields.Datetime(string='Create date', store=True, + default=fields.Datetime.now) + user_id = fields.Many2one('res.users', string='Salesperson', store=True, + related='subscription_id.user_id') + product_id = fields.Many2one('product.product', string='Product', + store=True, ondelete='restrict', + domain=[('is_subscription', '=', True)]) + product_qty = fields.Float(string='Quantity', store=True, default=1.0) + product_uom_id = fields.Many2one('uom.uom', string='UoM', store=True, + related='product_id.uom_id', + ondelete='restrict') + uom_catg_id = fields.Many2one('uom.category', string='UoM', store=True, + related='product_id.uom_id.category_id') + unit_price = fields.Float(string='Unit Price', store=True, readonly=False, + related='product_id.list_price') + currency_id = fields.Many2one('res.currency', string='Currency', + store=True, + related='subscription_id.currency_id') + total_amount = fields.Monetary(string='Subtotal', store=True, + compute='_compute_total_amount') + sequence = fields.Integer('Sequence', help="Determine the display order", + index=True) + res_partner_id = fields.Many2one('res.partner', string='Currency', + store=True, + related='subscription_id.partner_id') + + @api.depends('product_qty', 'unit_price') + def _compute_total_amount(self): + """ Calculate subtotal amount of product line """ + for rec in self: + if rec.product_id: + rec.total_amount = rec.unit_price * rec.product_qty + + +class SubscriptionPackage(models.Model): + _name = 'subscription.package' + _description = 'Subscription Package' + _rec_name = 'name' + _inherit = ['mail.thread', 'mail.activity.mixin'] + + @api.model + def _read_group_stage_ids(self, categories, domain, order): + """ Read all the stages and display it in the kanban view, + even if it is empty.""" + category_ids = categories._search([], order=order, + access_rights_uid=SUPERUSER_ID) + return categories.browse(category_ids) + + def _default_stage_id(self): + """Setting default stage""" + rec = self.env['subscription.package.stage'].search([], limit=1, + order='sequence ASC') + return rec.id if rec else None + + name = fields.Char(string='Name', default="New", compute='_compute_name', + store=True, required=True) + partner_id = fields.Many2one('res.partner', string='Customer', store=True) + partner_invoice_id = fields.Many2one('res.partner', + string='Invoice Address', + related='partner_id', readonly=False) + partner_shipping_id = fields.Many2one('res.partner', + string='Shipping/Service Address', + related='partner_id', + readonly=False) + plan_id = fields.Many2one('subscription.package.plan', + string='Subscription Plan') + start_date = fields.Date(string='Start Date', store=True, + ondelete='restrict') + next_invoice_date = fields.Date(string='Next Invoice Date', readonly=False, + store=True, + compute="_compute_next_invoice_date") + company_id = fields.Many2one('res.company', string='Company', + default=lambda self: self.env.company, + required=True) + user_id = fields.Many2one('res.users', string='Sales Person', + default=lambda self: self.env.user) + sale_order = fields.Many2one('sale.order', string="Sale Order") + to_renew = fields.Boolean(string='To Renew', default=False) + tag_ids = fields.Many2many('account.analytic.tag', string='Tags') + stage_id = fields.Many2one('subscription.package.stage', string='Stage', + default=lambda self: self._default_stage_id(), + index=True, + group_expand='_read_group_stage_ids') + invoice_count = fields.Integer(string='Invoices', + compute='_compute_invoice_count') + so_count = fields.Integer(string='Sales', compute='_compute_sale_count') + description = fields.Text(string='Description') + analytic_account_id = fields.Many2one('account.analytic.account', + string='Analytic Account') + product_line_ids = fields.One2many('subscription.package.product.line', + 'subscription_id', ondelete='restrict', + string='Products Line') + currency_id = fields.Many2one('res.currency', string='Currency', + readonly=True, + default=lambda + self: self.env.company.currency_id) + current_stage = fields.Char(string='Current Stage', default='Draft', + store=True, compute='_compute_current_stage') + reference_code = fields.Char(string='Reference', store=True) + is_closed = fields.Boolean(string="Closed", default=False) + close_reason = fields.Many2one('subscription.package.stop', + string='Close Reason') + closed_by = fields.Many2one('res.users', string='Closed By') + close_date = fields.Date(string='Closed on') + stage_category = fields.Selection(related='stage_id.category', store=True) + invoice_mode = fields.Selection(related="plan_id.invoice_mode") + total_recurring_price = fields.Float(string='Recurring Price', + compute='_compute_total_recurring_price', + store=True) + + @api.depends('invoice_count') + def _compute_invoice_count(self): + """ Calculate Invoice count based on subscription package """ + invoice_count = self.env['account.move'].search_count( + [('subscription_id', '=', self.id)]) + if invoice_count > 0: + self.invoice_count = invoice_count + else: + self.invoice_count = 0 + + @api.depends('so_count') + def _compute_sale_count(self): + """ Calculate sale order count based on subscription package """ + self.so_count = self.env['sale.order'].search_count( + [('subscription_id', '=', self.id)]) + + @api.depends('stage_id') + def _compute_current_stage(self): + """ It displays current stage for subscription package """ + for rec in self: + rec.current_stage = rec.env['subscription.package.stage'].search( + [('id', '=', rec.stage_id.id)]).category + + @api.depends('start_date') + def _compute_next_invoice_date(self): + pending_subscriptions = self.env['subscription.package'].search( + [('stage_category', '=', 'progress')]) + for sub in pending_subscriptions: + if sub.start_date: + sub.next_invoice_date = sub.start_date + relativedelta( + days=sub.plan_id.renewal_time) + + def button_invoice_count(self): + """ It displays invoice based on subscription package """ + return { + 'name': 'Invoices', + 'domain': [('subscription_id', '=', self.id)], + 'view_type': 'form', + 'res_model': 'account.move', + 'view_mode': 'tree,form', + 'type': 'ir.actions.act_window', + 'context': { + "create": False + } + } + + def button_sale_count(self): + """ It displays sale order based on subscription package """ + return { + 'name': 'Products', + 'domain': [('subscription_id', '=', self.id)], + 'view_type': 'form', + 'res_model': 'sale.order', + 'view_mode': 'tree,form', + 'type': 'ir.actions.act_window', + 'context': { + "create": False + } + } + + def button_close(self): + """ Button for subscription close wizard """ + return { + 'name': "Subscription Close Reason", + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'subscription.close.wizard', + 'target': 'new' + } + + def button_payment(self): + """ Button to create invoice for subscription package""" + this_products_line = [] + for rec in self.product_line_ids: + rec_list = [0, 0, {'product_id': rec.product_id.id, + 'quantity': rec.product_qty}] + this_products_line.append(rec_list) + invoices = self.env['account.move'].search([('subscription_id', '=', self.id), ('state', '=', 'draft')]) + orders = self.env['sale.order'].search([('subscription_id', '=', self.id), ('invoice_status', '=', 'no')]) + if invoices: + for invoice in invoices: + invoice.action_post() + if orders and invoices: + for order in orders: + order.action_confirm() + for invoice in invoices: + invoice.action_post() + out_invoice = self.env['account.move'].create( + { + 'move_type': 'out_invoice', + 'date': fields.Date.today(), + 'invoice_date': fields.Date.today(), + 'partner_id': self.partner_invoice_id.id, + 'currency_id': self.partner_invoice_id.currency_id.id, + 'invoice_line_ids': this_products_line + }) + self.env['account.move'].payment_id = out_invoice.id + if self.stage_category == 'progress': + values = {'start_date': datetime.datetime.today()} + self.write(values) + return { + 'name': 'Subscription Payment', + 'type': 'ir.actions.act_window', + 'res_model': 'account.move', + 'view_mode': 'form', + 'res_id': out_invoice.id + } + + def button_start_date(self): + """Button to start subscription package""" + if not self.start_date: + self.start_date = datetime.date.today() + for rec in self: + if len(rec.env['subscription.package.stage'].search([('category', '=', 'draft')])) > 1: + raise UserError( + _('More than one stage is having category "Draft". ' + 'Please change category of stage to "In Progress", ' + 'only one stage is allowed to have category "Draft"')) + else: + rec.write( + {'stage_id': (rec.env['subscription.package.stage'].search([ + ('category', '=', 'draft')]).id) + 1}) + + def button_sale_order(self): + """Button to create sale order""" + this_products_line = [] + for rec in self.product_line_ids: + rec_list = [0, 0, {'product_id': rec.product_id.id, + 'product_uom_qty': rec.product_qty}] + this_products_line.append(rec_list) + # for order in self.sale_order: + orders = self.env['sale.order'].search([('subscription_id', '=', self.id), ('invoice_status', '=', 'no')]) + if orders: + for order in orders: + order.action_confirm() + so_id = self.env['sale.order'].create({ + 'partner_id': self.partner_id.id, + 'partner_invoice_id': self.partner_id.id, + 'partner_shipping_id': self.partner_id.id, + 'is_subscription': True, + 'subscription_id': self.id, + 'order_line': this_products_line + }) + self.sale_order = so_id + return { + 'name': _('Sales Orders'), + 'type': 'ir.actions.act_window', + 'res_model': 'sale.order', + 'domain': [('id', '=', so_id.id)], + 'view_mode': 'tree,form' + } + + @api.model + def create(self, vals): + """It displays subscription product in partner and generate sequence""" + partner = self.env['res.partner'].search( + [('id', '=', vals.get('partner_id'))]) + partner.active_subscription = True + if vals.get('reference_code', 'New') is False: + vals['reference_code'] = self.env['ir.sequence'].next_by_code( + 'sequence.reference.code') or 'New' + create_id = super(SubscriptionPackage, self).create(vals) + return create_id + + @api.depends('reference_code') + def _compute_name(self): + """It displays record name as combination of short code, reference + code and partner name """ + plan_id = self.env['subscription.package.plan'].search( + [('id', '=', self.plan_id.id)]) + if plan_id.short_code and self.reference_code: + self.name = plan_id.short_code + '/' + self.reference_code + '-' + self.partner_id.name + + def set_close(self): + """ Button to close subscription package """ + stage = self.env['subscription.package.stage'].search( + [('category', '=', 'closed')], limit=1).id + for sub in self: + values = {'stage_id': stage, 'to_renew': False} + sub.write(values) + return True + + def close_limit_cron(self): + """ It Checks renew date, close date. It will send mail when renew date """ + pending_subscriptions = self.env['subscription.package'].search( + [('stage_category', '=', 'progress')]) + today_date = fields.Date.today() + pending_subscription = False + close_subscription = False + for pending_subscription in pending_subscriptions: + pending_subscription.close_date = pending_subscription.start_date + relativedelta( + days=pending_subscription.plan_id.days_to_end) + difference = ( + pending_subscription.close_date - pending_subscription.start_date).days / 10 + renew_date = pending_subscription.close_date - relativedelta( + days=difference) + if today_date == renew_date: + self.env.ref( + 'subscription_package.mail_template_subscription_renew').send_mail( + pending_subscription.id, force_send=True) + pending_subscription.write({'to_renew': True}) + if pending_subscription.plan_id.invoice_mode == 'draft_invoice': + this_products_line = [] + for rec in pending_subscription.product_line_ids: + rec_list = [0, 0, {'product_id': rec.product_id.id, + 'quantity': rec.product_qty}] + this_products_line.append(rec_list) + self.env['account.move'].create( + { + 'move_type': 'out_invoice', + 'date': fields.Date.today(), + 'invoice_date': fields.Date.today(), + 'state': 'draft', + 'partner_id': pending_subscription.partner_invoice_id.id, + 'currency_id': pending_subscription.partner_invoice_id.currency_id.id, + 'invoice_line_ids': this_products_line + }) + pending_subscription.write({'to_renew': False, + 'start_date': datetime.datetime.today()}) + close_subscriptions = self.env['subscription.package'].search( + [('stage_category', '=', 'progress'), ('to_renew', '=', True)]) + for close_subscription in close_subscriptions: + close_subscription.close_date = close_subscription.start_date + relativedelta( + days=close_subscription.plan_id.days_to_end) + if today_date == close_subscription.close_date: + close_subscription.set_close() + return dict(pending=pending_subscription, closed=close_subscription) + + @api.depends('product_line_ids.total_amount') + def _compute_total_recurring_price(self): + """ Calculate recurring price """ + for record in self: + total_recurring = 0 + for line in record.product_line_ids: + total_recurring += line.total_amount + record['total_recurring_price'] = total_recurring + + def action_renew(self): + return self.button_sale_order() diff --git a/subscription_package/models/subscription_plan.py b/subscription_package/models/subscription_plan.py new file mode 100644 index 000000000..db553fbf3 --- /dev/null +++ b/subscription_package/models/subscription_plan.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import api, models, fields + + +class SubscriptionPlan(models.Model): + _name = 'subscription.package.plan' + _description = 'Subscription Package Plan' + + name = fields.Char(string='Plan Name', required=True) + renewal_value = fields.Char(string='Renewal') + renewal_period = fields.Selection([('days', 'Day(s)'), + ('weeks', 'Week(s)'), + ('months', 'Month(s)'), + ('years', 'Year(s)')], + default='months') + renewal_time = fields.Integer(string='Renewal Time Interval', + readonly=True, + compute='_compute_renewal_time', + store=True) + limit_choice = fields.Selection([('ones', 'Ones'), + ('manual', 'Until Closed Manually'), + ('custom', 'Custom')], + default='ones') + limit_count = fields.Integer(string='Custom Renewal Limit') + days_to_end = fields.Integer(string='Days End', readonly=True, + compute='_compute_days_to_end', store=True, + help="Subscription ending date") + invoice_mode = fields.Selection([('manual', 'Manually'), + ('draft_invoice', 'Draft')], + default='draft_invoice') + journal_id = fields.Many2one('account.journal', string='Journal', + store=True, domain="[('type', '=', 'sale')]") + company_id = fields.Many2one('res.company', string='Company', store=True, + default=lambda self: self.env.company) + short_code = fields.Char(string='Short Code') + terms_and_conditions = fields.Text(string='Terms and Conditions') + product_count = fields.Integer(string='Products', + compute='_compute_product_count') + subscription_count = fields.Integer(string='Subscriptions', + compute='_compute_subscription_count') + + @api.depends('product_count') + def _compute_product_count(self): + """ Calculate product count based on subscription plan """ + self.product_count = self.env['product.product'].search_count( + [('subscription_plan_id', '=', self.id)]) + + @api.depends('subscription_count') + def _compute_subscription_count(self): + """ Calculate subscription count based on subscription plan """ + self.subscription_count = self.env[ + 'subscription.package'].search_count([('plan_id', '=', self.id)]) + + @api.depends('renewal_value', 'renewal_period') + def _compute_renewal_time(self): + """ This method calculate renewal time based on renewal value """ + for rec in self: + if rec.renewal_period == 'days': + rec.renewal_time = int(rec.renewal_value) + elif rec.renewal_period == 'weeks': + rec.renewal_time = int(rec.renewal_value) * 7 + elif rec.renewal_period == 'months': + rec.renewal_time = int(rec.renewal_value) * 28 + elif rec.renewal_period == 'years': + rec.renewal_time = int(rec.renewal_value) * 364 + if rec.name: + rec.short_code = str(rec.name[0:3]).upper() + + @api.depends('renewal_time', 'limit_count') + def _compute_days_to_end(self): + """ This method calculate days to end for subscription plan based on + limit count """ + for rec in self: + if rec.limit_choice == 'ones': + rec.days_to_end = rec.renewal_time + if rec.limit_choice == 'manual': + rec.days_to_end = False + if rec.limit_choice == 'custom': + rec.days_to_end = rec.renewal_time * rec.limit_count + + def button_product_count(self): + """ It displays products based on subscription plan """ + return { + 'name': 'Products', + 'domain': [('subscription_plan_id', '=', self.id)], + 'view_type': 'form', + 'res_model': 'product.product', + 'view_mode': 'tree,form', + 'type': 'ir.actions.act_window', + } + + def button_sub_count(self): + """ It displays subscriptions based on subscription plan """ + return { + 'name': 'Subscriptions', + 'domain': [('plan_id', '=', self.id)], + 'view_type': 'form', + 'res_model': 'subscription.package', + 'view_mode': 'tree,form', + 'type': 'ir.actions.act_window', + } + + def name_get(self): + """ It displays record name as combination of short code and + plan name """ + res = [] + for rec in self: + res.append((rec.id, '%s - %s' % (rec.short_code, rec.name))) + return res diff --git a/subscription_package/models/subscription_products.py b/subscription_package/models/subscription_products.py new file mode 100644 index 000000000..1d3df8832 --- /dev/null +++ b/subscription_package/models/subscription_products.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import api, models, fields + + +class SubscriptionInvoice(models.Model): + _inherit = "account.move" + + is_subscription = fields.Boolean(string='Is Subscription', default=False) + subscription_id = fields.Many2one('subscription.package', + string='Subscription') + + @api.model_create_multi + def create(self, vals_list): + """ It displays subscription in account move """ + for rec in vals_list: + so_id = self.env['sale.order'].search( + [('name', '=', rec.get('invoice_origin'))]) + if so_id.is_subscription is True: + new_vals_list = [{'is_subscription': True, + 'subscription_id': so_id.subscription_id}] + vals_list[0].update(new_vals_list[0]) + return super(SubscriptionInvoice, self).create(vals_list) + + +class SubscriptionProduct(models.Model): + _inherit = "product.template" + + is_subscription = fields.Boolean(string='Is Subscription', default=False) + subscription_plan_id = fields.Many2one('subscription.package.plan', + string='Subscription Plan') diff --git a/subscription_package/models/subscription_renew.py b/subscription_package/models/subscription_renew.py new file mode 100644 index 000000000..899e21277 --- /dev/null +++ b/subscription_package/models/subscription_renew.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import api, models, fields +import datetime + + +class SubscriptionSaleOrder(models.Model): + _inherit = "sale.order" + + is_subscription = fields.Boolean(string='Is Subscription', default=False) + subscription_id = fields.Many2one('subscription.package', + string='Subscription') + sub_reference = fields.Char(string="Sub Reference Code", store=True, + compute="_compute_reference_code") + + @api.model + def create(self, vals): + """ It displays subscription in sale order """ + if vals.get('is_subscription') is True: + new_vals = [{ + 'is_subscription': True, + 'subscription_id': vals.get('subscription_id'), + }] + vals.update(new_vals[0]) + return super(SubscriptionSaleOrder, self).create(vals) + else: + return super(SubscriptionSaleOrder, self).create(vals) + + @api.depends('subscription_id') + def _compute_reference_code(self): + """ It displays subscription reference code """ + self.sub_reference = self.env['subscription.package'].search( + [('id', '=', int(self.subscription_id.id))]).reference_code + + def action_confirm(self): + """ It Changed the stage, to renew, start date for subscription + package based on sale order confirm """ + + res = super(SubscriptionSaleOrder, self).action_confirm() + sale_order = self.subscription_id.sale_order + so_state = self.search([('id', '=', sale_order.id)]).state + if so_state in ['sale', 'done']: + stage = self.env['subscription.package.stage'].search( + [('category', '=', 'progress')], limit=1).id + values = {'stage_id': stage, 'to_renew': False, + 'start_date': datetime.datetime.today()} + self.subscription_id.write(values) + return res diff --git a/subscription_package/models/subscription_stage.py b/subscription_package/models/subscription_stage.py new file mode 100644 index 000000000..8fa2e02c4 --- /dev/null +++ b/subscription_package/models/subscription_stage.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import models, fields + + +class SubscriptionPackageStage(models.Model): + _name = "subscription.package.stage" + _description = "Subscription Package Stages" + _rec_name = 'name' + + name = fields.Char(string='Stage Name', required=True) + sequence = fields.Integer('Sequence', help="Determine the display order", + index=True) + condition = fields.Text(string='Conditions') + fold = fields.Boolean(string='Folded in Kanban', + help="This stage is folded in the kanban view " + "when there are no records in that stage " + "to display.") + category = fields.Selection([('draft', 'Draft'), + ('progress', 'In Progress'), + ('closed', 'Closed')], + readonly=False, default='draft') diff --git a/subscription_package/report/__init__.py b/subscription_package/report/__init__.py new file mode 100644 index 000000000..d2cd434d0 --- /dev/null +++ b/subscription_package/report/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from . import subscription_report diff --git a/subscription_package/report/subscription_report.py b/subscription_package/report/subscription_report.py new file mode 100644 index 000000000..27ef19c96 --- /dev/null +++ b/subscription_package/report/subscription_report.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import models, fields +from odoo import tools + + +class SubscriptionReport(models.Model): + _name = "subscription.report" + _description = "Subscription Analysis" + _auto = False + + total_recurring_price = fields.Float('Recurring Price', readonly=True) + quantity = fields.Float('Quantity', readonly=True) + user_id = fields.Many2one('res.users', 'Salesperson', readonly=True) + plan_id = fields.Many2one('subscription.package.plan', 'Subscription Template', readonly=True) + + def _query(self): + select_ = """ + SELECT min(sl.id) as id, + sl.product_qty as quantity, + sub.total_recurring_price as total_recurring_price, + sub.user_id as user_id, + sub.plan_id as plan_id, + sub.name as name + """ + from_ = """ + subscription_package_product_line sl + join subscription_package sub on (sl.subscription_id = sub.id) + """ + groupby_ = """ + GROUP BY sl.product_qty, + sub.total_recurring_price, + sub.user_id, + sub.plan_id, + sub.name + """ + return '%s FROM ( %s ) %s' % (select_, from_, groupby_) + + def init(self): + tools.drop_view_if_exists(self.env.cr, self._table) + self.env.cr.execute("""CREATE or REPLACE VIEW %s as (%s)""" % ( + self._table, self._query())) diff --git a/subscription_package/report/subscription_report_view.xml b/subscription_package/report/subscription_report_view.xml new file mode 100644 index 000000000..c32147236 --- /dev/null +++ b/subscription_package/report/subscription_report_view.xml @@ -0,0 +1,37 @@ + + + + + Subscription Report Pivot + subscription.report + + + + + + + + + + Subscription Report Graph + subscription.report + + + + + + + + + Subscriptions Report + subscription.report + pivot,graph + + + + + \ No newline at end of file diff --git a/subscription_package/security/ir.model.access.csv b/subscription_package/security/ir.model.access.csv new file mode 100644 index 000000000..523bde9ae --- /dev/null +++ b/subscription_package/security/ir.model.access.csv @@ -0,0 +1,8 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_subscription_package_plan,subscription.package_plan,model_subscription_package_plan,base.group_user,1,1,1,1 +access_subscription_package_stage,subscription.package.stage,model_subscription_package_stage,base.group_user,1,1,1,1 +access_subscription_package,subscription.package,model_subscription_package,base.group_user,1,1,1,1 +access_subscription_report,subscription.report,model_subscription_report,base.group_user,1,1,1,1 +access_subscription_package_product_line,subscription.package.product.line,model_subscription_package_product_line,base.group_user,1,1,1,1 +access_subscription_package_stop,subscription.package.stop,model_subscription_package_stop,base.group_user,1,1,1,1 +access_subscription_close_wizard,access.subscription.close.wizard,model_subscription_close_wizard,base.group_user,1,1,1,1 diff --git a/subscription_package/security/security.xml b/subscription_package/security/security.xml new file mode 100644 index 000000000..0e010a2ea --- /dev/null +++ b/subscription_package/security/security.xml @@ -0,0 +1,25 @@ + + + + + + Subscription + Helps you handle your subscription security. + 9 + + + + User + + + + + + Subscription Administrator + + + + + + + diff --git a/subscription_package/static/description/assets/icons/check.png b/subscription_package/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/subscription_package/static/description/assets/icons/check.png differ diff --git a/subscription_package/static/description/assets/icons/chevron.png b/subscription_package/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/subscription_package/static/description/assets/icons/chevron.png differ diff --git a/subscription_package/static/description/assets/icons/cogs.png b/subscription_package/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/subscription_package/static/description/assets/icons/cogs.png differ diff --git a/subscription_package/static/description/assets/icons/consultation.png b/subscription_package/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/subscription_package/static/description/assets/icons/consultation.png differ diff --git a/subscription_package/static/description/assets/icons/ecom-black.png b/subscription_package/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/subscription_package/static/description/assets/icons/ecom-black.png differ diff --git a/subscription_package/static/description/assets/icons/education-black.png b/subscription_package/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/subscription_package/static/description/assets/icons/education-black.png differ diff --git a/subscription_package/static/description/assets/icons/hotel-black.png b/subscription_package/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/subscription_package/static/description/assets/icons/hotel-black.png differ diff --git a/subscription_package/static/description/assets/icons/license.png b/subscription_package/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/subscription_package/static/description/assets/icons/license.png differ diff --git a/subscription_package/static/description/assets/icons/lifebuoy.png b/subscription_package/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/subscription_package/static/description/assets/icons/lifebuoy.png differ diff --git a/subscription_package/static/description/assets/icons/logo.png b/subscription_package/static/description/assets/icons/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/subscription_package/static/description/assets/icons/logo.png differ diff --git a/subscription_package/static/description/assets/icons/manufacturing-black.png b/subscription_package/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/subscription_package/static/description/assets/icons/manufacturing-black.png differ diff --git a/subscription_package/static/description/assets/icons/pos-black.png b/subscription_package/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/subscription_package/static/description/assets/icons/pos-black.png differ diff --git a/subscription_package/static/description/assets/icons/puzzle.png b/subscription_package/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/subscription_package/static/description/assets/icons/puzzle.png differ diff --git a/subscription_package/static/description/assets/icons/restaurant-black.png b/subscription_package/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/subscription_package/static/description/assets/icons/restaurant-black.png differ diff --git a/subscription_package/static/description/assets/icons/service-black.png b/subscription_package/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/subscription_package/static/description/assets/icons/service-black.png differ diff --git a/subscription_package/static/description/assets/icons/trading-black.png b/subscription_package/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/subscription_package/static/description/assets/icons/trading-black.png differ diff --git a/subscription_package/static/description/assets/icons/training.png b/subscription_package/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/subscription_package/static/description/assets/icons/training.png differ diff --git a/subscription_package/static/description/assets/icons/update.png b/subscription_package/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/subscription_package/static/description/assets/icons/update.png differ diff --git a/subscription_package/static/description/assets/icons/user.png b/subscription_package/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/subscription_package/static/description/assets/icons/user.png differ diff --git a/subscription_package/static/description/assets/icons/wrench.png b/subscription_package/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/subscription_package/static/description/assets/icons/wrench.png differ diff --git a/subscription_package/static/description/assets/modules/automatic_image.png b/subscription_package/static/description/assets/modules/automatic_image.png new file mode 100644 index 000000000..a49c2a820 Binary files /dev/null and b/subscription_package/static/description/assets/modules/automatic_image.png differ diff --git a/subscription_package/static/description/assets/modules/budget_image.png b/subscription_package/static/description/assets/modules/budget_image.png new file mode 100644 index 000000000..b50130c7d Binary files /dev/null and b/subscription_package/static/description/assets/modules/budget_image.png differ diff --git a/subscription_package/static/description/assets/modules/crm_dashboard_image.png b/subscription_package/static/description/assets/modules/crm_dashboard_image.png new file mode 100644 index 000000000..6547c3081 Binary files /dev/null and b/subscription_package/static/description/assets/modules/crm_dashboard_image.png differ diff --git a/subscription_package/static/description/assets/modules/crm_image.png b/subscription_package/static/description/assets/modules/crm_image.png new file mode 100644 index 000000000..8793336c0 Binary files /dev/null and b/subscription_package/static/description/assets/modules/crm_image.png differ diff --git a/subscription_package/static/description/assets/modules/crm_kit_image.png b/subscription_package/static/description/assets/modules/crm_kit_image.png new file mode 100644 index 000000000..0bbad468d Binary files /dev/null and b/subscription_package/static/description/assets/modules/crm_kit_image.png differ diff --git a/subscription_package/static/description/assets/modules/employee_image.png b/subscription_package/static/description/assets/modules/employee_image.png new file mode 100644 index 000000000..30ad58232 Binary files /dev/null and b/subscription_package/static/description/assets/modules/employee_image.png differ diff --git a/subscription_package/static/description/assets/modules/ip_image.png b/subscription_package/static/description/assets/modules/ip_image.png new file mode 100644 index 000000000..707e2b7ed Binary files /dev/null and b/subscription_package/static/description/assets/modules/ip_image.png differ diff --git a/subscription_package/static/description/assets/modules/payable_image.png b/subscription_package/static/description/assets/modules/payable_image.png new file mode 100644 index 000000000..fd1059dec Binary files /dev/null and b/subscription_package/static/description/assets/modules/payable_image.png differ diff --git a/subscription_package/static/description/assets/modules/product_custom_image.png b/subscription_package/static/description/assets/modules/product_custom_image.png new file mode 100644 index 000000000..9c34fd89f Binary files /dev/null and b/subscription_package/static/description/assets/modules/product_custom_image.png differ diff --git a/subscription_package/static/description/assets/modules/salesperson_image.png b/subscription_package/static/description/assets/modules/salesperson_image.png new file mode 100644 index 000000000..958ed2bf4 Binary files /dev/null and b/subscription_package/static/description/assets/modules/salesperson_image.png differ diff --git a/subscription_package/static/description/assets/modules/task_deadline_image.png b/subscription_package/static/description/assets/modules/task_deadline_image.png new file mode 100644 index 000000000..c128be58a Binary files /dev/null and b/subscription_package/static/description/assets/modules/task_deadline_image.png differ diff --git a/subscription_package/static/description/assets/screenshots/activity_type.png b/subscription_package/static/description/assets/screenshots/activity_type.png new file mode 100644 index 000000000..a4d83a37c Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/activity_type.png differ diff --git a/subscription_package/static/description/assets/screenshots/close_reason.png b/subscription_package/static/description/assets/screenshots/close_reason.png new file mode 100644 index 000000000..faebed6a9 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/close_reason.png differ diff --git a/subscription_package/static/description/assets/screenshots/create_sub.png b/subscription_package/static/description/assets/screenshots/create_sub.png new file mode 100644 index 000000000..86216c669 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/create_sub.png differ diff --git a/subscription_package/static/description/assets/screenshots/create_sub_plan.png b/subscription_package/static/description/assets/screenshots/create_sub_plan.png new file mode 100644 index 000000000..a8877cabf Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/create_sub_plan.png differ diff --git a/subscription_package/static/description/assets/screenshots/create_sub_stage.png b/subscription_package/static/description/assets/screenshots/create_sub_stage.png new file mode 100644 index 000000000..c64b358fb Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/create_sub_stage.png differ diff --git a/subscription_package/static/description/assets/screenshots/hero.gif b/subscription_package/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..b36c0bb5d Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/hero.gif differ diff --git a/subscription_package/static/description/assets/screenshots/sub_customer.png b/subscription_package/static/description/assets/screenshots/sub_customer.png new file mode 100644 index 000000000..4032b474d Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/sub_customer.png differ diff --git a/subscription_package/static/description/assets/screenshots/sub_package.png b/subscription_package/static/description/assets/screenshots/sub_package.png new file mode 100644 index 000000000..0e4e205e4 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/sub_package.png differ diff --git a/subscription_package/static/description/assets/screenshots/sub_product.png b/subscription_package/static/description/assets/screenshots/sub_product.png new file mode 100644 index 000000000..100df1316 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/sub_product.png differ diff --git a/subscription_package/static/description/assets/screenshots/sub_renew.png b/subscription_package/static/description/assets/screenshots/sub_renew.png new file mode 100644 index 000000000..310710132 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/sub_renew.png differ diff --git a/subscription_package/static/description/assets/screenshots/sub_report.png b/subscription_package/static/description/assets/screenshots/sub_report.png new file mode 100644 index 000000000..ac86eede5 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/sub_report.png differ diff --git a/subscription_package/static/description/assets/screenshots/sub_sale.png b/subscription_package/static/description/assets/screenshots/sub_sale.png new file mode 100644 index 000000000..2c9178958 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/sub_sale.png differ diff --git a/subscription_package/static/description/assets/screenshots/sub_stage.png b/subscription_package/static/description/assets/screenshots/sub_stage.png new file mode 100644 index 000000000..b131b4166 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/sub_stage.png differ diff --git a/subscription_package/static/description/assets/screenshots/subscription_plan.png b/subscription_package/static/description/assets/screenshots/subscription_plan.png new file mode 100644 index 000000000..80b54ce07 Binary files /dev/null and b/subscription_package/static/description/assets/screenshots/subscription_plan.png differ diff --git a/subscription_package/static/description/banner.png b/subscription_package/static/description/banner.png new file mode 100644 index 000000000..a5acbabc2 Binary files /dev/null and b/subscription_package/static/description/banner.png differ diff --git a/subscription_package/static/description/icon.png b/subscription_package/static/description/icon.png new file mode 100644 index 000000000..0ef49ff1a Binary files /dev/null and b/subscription_package/static/description/icon.png differ diff --git a/subscription_package/static/description/index.html b/subscription_package/static/description/index.html new file mode 100644 index 000000000..2cdd79161 --- /dev/null +++ b/subscription_package/static/description/index.html @@ -0,0 +1,719 @@ +
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+ +
+
+
+
+ +
+
+
+

+ Subscription Package

+

+ Print Subscription Package +

+ +
+
+ + + + +
+
+

+ Overview +

+
+ +
+

+ + This module is used to generate subscription package

+ +
+
+ + +
+
+

+ Features +

+
+ +
+
+ +
+
+

+ Community & Enterprise Support

+

+ Available in Odoo 15.0 Community and Enterprise.

+
+
+
+
+ +
+
+

+ Subscription Package Plan

+
+
+ +
+
+ +
+
+

+ Subscription Renewable

+
+
+ +
+
+ +
+
+

+ Automatic Subscription Closed

+
+
+ +
+
+ +
+
+

+ Renew Email Alerts

+
+
+ +
+
+ +
+
+

+ Create Subscription Plans

+
+
+ +
+
+ +
+
+

+ Recurring Invoices Daily/Weekly/Monthly/Yearly

+
+
+ +
+ +
+
+

+ Screenshots +

+
+
+

+ Subscription Plans

+ +
+ +
+

+ Create Subscription Plan

+

+

    +
  • First of all, You will create a Subscription Plan.
  • +
  • In Subscription Plan we have a Radio Button named 'Number of Occurrence',
    + - if we choose 'Ones', then this plan will expire according to 'Invoice on' time interval.
    + - if we choose 'Until Closed Manually', then this plan will expire only after clicking the button 'Close + Subscription'.
    + - if we choose 'Custom', then this plan will expire according to 'Invoice on' time interval and 'Renewal + Limit'. +
  • +
  • In Subscription Plan we have a Radio Button named 'Create Invoice',
  • + - If we choose 'Manually', then invoice creation is manually.
    + - If we choose 'Draft', then invoice creation is automatically.
    +
+

+ +
+ +
+

+ Create Subscription Product

+

+

    +
  • First of all, You will create a Product.
  • +
  • Here we have a CheckBox named 'Is Subscription', if we Enable the Checkbox, then the product is + subscription + product.
  • +
  • Now we choose a Subscription Plan for the period.
  • +
+

+ +
+ +
+

+ Create Subscription Customer

+

+

    +
  • First of all, You will create a Customer.
  • +
  • Here we have a page 'Subscription' that show subscription product for customer.
  • +
+

+ +
+ +
+

+ Activity Types

+ +
+ +
+

+ Subscription Close Reasons

+ +
+ +
+

+ Subscription Stages

+ +
+ +
+

+ Create Subscription Stage

+ +
+ +
+

+ Subscription Report

+

+ It shows report for subscription plans. +

+ +
+ +
+

+ Subscriptions to Renew

+ +
+ +
+

+ Create Subscription Package with Sale Order

+ +
+ +
+

+

    +
  • To create a Subscription with source 'Create Sale Order', Create a Quotation of Sale Order with at least + one + subscription type product in the order line.
  • +
  • When we click on the 'Confirm' button on the 'Sale Quotation' then, automatically a subscription is + created + in 'In-progress' state.
  • +
+

+ +
+ +
+ + +
+
+

Suggested Products

+
+ + +
+
+ + + +
+
+
+

Our Services

+
+
+ +
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + + +
+
+
+

Our Industries

+
+
+ +
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+ +
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+ +
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+ +
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+ +
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+ +
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+ +
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+ +
+
+ + + + + +
+
+
+

Need Help?

+
+
+
+ + +
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ + +
\ No newline at end of file diff --git a/subscription_package/views/mail_activity_views.xml b/subscription_package/views/mail_activity_views.xml new file mode 100644 index 000000000..1b7da4426 --- /dev/null +++ b/subscription_package/views/mail_activity_views.xml @@ -0,0 +1,18 @@ + + + + + Activity Types + mail.activity.type + tree,form + ['|', ('res_model', '=', False), ('res_model', '=', 'subscription.package')] + {'default_res_model': 'subscription.package'} + + + + + \ No newline at end of file diff --git a/subscription_package/views/res_partner.xml b/subscription_package/views/res_partner.xml new file mode 100644 index 000000000..c8c938bfc --- /dev/null +++ b/subscription_package/views/res_partner.xml @@ -0,0 +1,27 @@ + + + + + inherit.subscription.partner.form + res.partner + + + + + + + + + + + + + + + + + + + + diff --git a/subscription_package/views/subscription_close.xml b/subscription_package/views/subscription_close.xml new file mode 100644 index 000000000..0c4e7c371 --- /dev/null +++ b/subscription_package/views/subscription_close.xml @@ -0,0 +1,27 @@ + + + + + Subscription Stop Reason + subscription.package.stop + tree + + + + Subscription Stop Reason Tree + subscription.package.stop + + + + + + + + + + + \ No newline at end of file diff --git a/subscription_package/views/subscription_package.xml b/subscription_package/views/subscription_package.xml new file mode 100644 index 000000000..0c312719f --- /dev/null +++ b/subscription_package/views/subscription_package.xml @@ -0,0 +1,272 @@ + + + + + + Reference Code + sequence.reference.code + SUB + 4 + + + + + Subscriptions + ir.actions.act_window + subscription.package + kanban,tree,form,pivot + +

+ Create a new subscription package ! +

+
+
+ + + Subscriptions Customers + ir.actions.act_window + res.partner + kanban,tree,form + [('active_subscription', '=', True)] + +

+ Create a new subscription package ! +

+
+
+ + + Subscriptions to Renew + ir.actions.act_window + subscription.package + [('to_renew', '=', True)] + kanban,tree,form,pivot + +

+ Create a new subscription package ! +

+
+
+ + + subscription.package.tree + subscription.package + + + + + + + + + + + + + subscription.package.form + subscription.package + + +
+
+ + +
+ +
+ + +
+
+

+ +

+
+ For Renewal +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + + subscription.package.kanban + subscription.package + + + + + + + + + + +
+
+
+ +
+
+ +
+
+ To Renew +
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + + + + + subscription.package.pivot + subscription.package + + + + + + + + + + + + + + + + + + diff --git a/subscription_package/views/subscription_plan.xml b/subscription_package/views/subscription_plan.xml new file mode 100644 index 000000000..ff4e64844 --- /dev/null +++ b/subscription_package/views/subscription_plan.xml @@ -0,0 +1,108 @@ + + + + + Subscription Plan + ir.actions.act_window + subscription.package.plan + tree,form + +

+ Create a new subscription plan ! +

+
+
+ + + subscription.package.plan.tree + subscription.package.plan + + + + + + + + + + + + subscription.package.plan.form + subscription.package.plan + +
+ +
+ + +
+
+

+

+
+ + + + + + + + + + + + + + +
+
+
+
+ + + + + +
diff --git a/subscription_package/views/subscription_products.xml b/subscription_package/views/subscription_products.xml new file mode 100644 index 000000000..93e645fc5 --- /dev/null +++ b/subscription_package/views/subscription_products.xml @@ -0,0 +1,86 @@ + + + + + Inherit Product Search + product.template + + 25 + + + + + + + + + + Inherit Product Product: Is Subscription Product + product.product + + 25 + + + + + + + + + + + + + + + + Inherit Product Template: Product Subscription + product.template + + 25 + + + + + + + + + + + + + + + + Products + ir.actions.act_window + product.template + kanban,tree,form,activity + + + { + 'search_default_filter_is_subscription': True, + 'search_default_filter_to_sell':1, + 'default_type':'service', + 'default_is_subscription':True} + +

+ Create a new product +

+
+
+ + + +
\ No newline at end of file diff --git a/subscription_package/views/subscription_renew.xml b/subscription_package/views/subscription_renew.xml new file mode 100644 index 000000000..4500e7688 --- /dev/null +++ b/subscription_package/views/subscription_renew.xml @@ -0,0 +1,21 @@ + + + + + sale.order.form.subscription.info + sale.order + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/subscription_package/views/subscription_stage.xml b/subscription_package/views/subscription_stage.xml new file mode 100644 index 000000000..73c7ffc5d --- /dev/null +++ b/subscription_package/views/subscription_stage.xml @@ -0,0 +1,51 @@ + + + + + Stages + subscription.package.stage + tree,form + + + + Subscription Stage Tree + subscription.package.stage + + + + + + + + + + Subscription Stage Form + subscription.package.stage + +
+ + + + + + + + + + + + + + +
+
+
+ + + +
\ No newline at end of file diff --git a/subscription_package/wizard/__init__.py b/subscription_package/wizard/__init__.py new file mode 100644 index 000000000..02b1d18ed --- /dev/null +++ b/subscription_package/wizard/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from . import subscription_close_wizard diff --git a/subscription_package/wizard/subscription_close_wizard.py b/subscription_package/wizard/subscription_close_wizard.py new file mode 100644 index 000000000..6bcd396c5 --- /dev/null +++ b/subscription_package/wizard/subscription_close_wizard.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2022-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# + +from odoo import models, fields, api + + +class SubscriptionCloseWizard(models.TransientModel): + _name = 'subscription.close.wizard' + _description = 'Subscription Close Wizard' + + close_reason = fields.Many2one('subscription.package.stop', string='Close Reason') + closed_by = fields.Many2one('res.users', string='Closed By', default=lambda self: self.env.user) + close_date = fields.Date(string='Closed On', default=lambda self: fields.Date.today()) + + def button_submit(self): + self.ensure_one() + this_sub_id = self.env.context.get('active_id') + sub = self.env['subscription.package'].search([('id', '=', this_sub_id)]) + sub.is_closed = True + sub.close_reason = self.close_reason + sub.closed_by = self.closed_by + sub.close_date = self.close_date + stage = (self.env['subscription.package.stage'].search([ + ('category', '=', 'closed')]).id) + values = {'stage_id': stage, 'to_renew': False} + sub.write(values) diff --git a/subscription_package/wizard/subscription_close_wizard.xml b/subscription_package/wizard/subscription_close_wizard.xml new file mode 100644 index 000000000..787d36a15 --- /dev/null +++ b/subscription_package/wizard/subscription_close_wizard.xml @@ -0,0 +1,23 @@ + + + + + subscription.close.wizard.view + subscription.close.wizard + +
+ + + + + + +
+
+
+ +
\ No newline at end of file