Files
encoach_backend_new_v2/odoo/addons/sale/models/utm_campaign.py
Yamen Ahmad 3e83d8d7d5 feat: add complete EnCoach backend — Odoo 19 + all addons
Includes:
- Odoo 19 framework (odoo/)
- 27 custom EnCoach addons (new_project/custom_addons/)
  - encoach_core, encoach_api, encoach_lms_api, encoach_adaptive_api
  - encoach_exam, encoach_taxonomy, encoach_adaptive, encoach_assignment
  - encoach_ai, encoach_ai_grading, encoach_ai_generation, encoach_ai_media
  - encoach_courseware, encoach_communication, encoach_subscription
  - encoach_notification, encoach_approval, encoach_branding
  - encoach_classroom, encoach_registration, encoach_stats
  - encoach_faq, encoach_ticket, encoach_training, encoach_resources
  - encoach_adaptive_ai, encoach_sis
- 21 OpenEduCat Enterprise modules (new_project/enterprise-19/)
- 14 OpenEduCat Community modules (new_project/openeducat_erp-19.0/)
- Configuration: odoo.conf, requirements.txt, scripts
- 200+ REST API endpoints with JWT authentication
- SRS and test documentation

Made-with: Cursor
2026-04-01 17:10:04 +04:00

73 lines
3.3 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
from odoo.tools import SQL
class UtmCampaign(models.Model):
_inherit = 'utm.campaign'
_description = 'UTM Campaign'
quotation_count = fields.Integer('Quotation Count',
compute="_compute_quotation_count", compute_sudo=True, groups='sales_team.group_sale_salesman')
invoiced_amount = fields.Integer(string="Revenues generated by the campaign",
compute="_compute_sale_invoiced_amount", compute_sudo=True, groups='sales_team.group_sale_salesman')
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company)
currency_id = fields.Many2one('res.currency', related='company_id.currency_id', string='Currency')
def _compute_quotation_count(self):
quotation_data = self.env['sale.order']._read_group([
('campaign_id', 'in', self.ids)],
['campaign_id'], ['__count'])
data_map = {campaign.id: count for campaign, count in quotation_data}
for campaign in self:
campaign.quotation_count = data_map.get(campaign.id, 0)
def _compute_sale_invoiced_amount(self):
if self.ids:
self.env['account.move.line'].flush_model(['balance', 'move_id', 'account_id', 'display_type'])
self.env['account.move'].flush_model(['state', 'campaign_id', 'move_type'])
query_res = self.env.execute_query_dict(SQL(
""" SELECT move.campaign_id, -SUM(line.balance) as price_subtotal
FROM account_move_line line
INNER JOIN account_move move ON line.move_id = move.id
WHERE move.state not in ('draft', 'cancel')
AND move.campaign_id IN %s
AND move.move_type IN ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt')
AND line.account_id IS NOT NULL
AND line.display_type = 'product'
GROUP BY move.campaign_id """,
tuple(self.ids),
))
else:
query_res = []
campaigns = self.browse()
for datum in query_res:
campaign = self.browse(datum['campaign_id'])
campaign.invoiced_amount = datum['price_subtotal']
campaigns |= campaign
for campaign in (self - campaigns):
campaign.invoiced_amount = 0
def action_redirect_to_quotations(self):
action = self.env["ir.actions.actions"]._for_xml_id("sale.action_quotations_with_onboarding")
action['domain'] = [('campaign_id', '=', self.id)]
action['context'] = {'default_campaign_id': self.id}
return action
def action_redirect_to_invoiced(self):
action = self.env["ir.actions.actions"]._for_xml_id("account.action_move_journal_line")
invoices = self.env['account.move'].search([('campaign_id', '=', self.id)])
action['context'] = {
'create': False,
'edit': False,
'view_no_maturity': True
}
action['domain'] = [
('id', 'in', invoices.ids),
('move_type', 'in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt')),
('state', 'not in', ['draft', 'cancel'])
]
return action