diff --git a/__manifest__.py b/__manifest__.py index ba3dc42..ef5782c 100755 --- a/__manifest__.py +++ b/__manifest__.py @@ -9,11 +9,12 @@ 'sequence': 20, 'summary': 'DigitalSignage Management', 'description': """DigitalSignage Management""", - 'depends':['base','mail','web'], + 'depends':['base','mail','web','website'], 'data': [ 'security/groups.xml', 'security/ir.model.access.csv', 'views/dss_contracts.xml', + 'views/dss_marker.xml', 'views/dss_projectstate.xml', 'views/dss_systemtypen.xml', 'views/dss_mediarelations.xml', @@ -30,17 +31,24 @@ 'views/dss_screendesign.xml', 'views/dss_eventdays.xml', 'views/dss_trigger_actions.xml', - 'views/dss_triggertypes.xml', + 'views/dss_trigger_action_groups.xml', + 'views/dss_trigger_execute.xml', + 'views/dss_triggertypes.xml', 'views/dss_trigger_groups.xml', + 'views/dss_trigger_conditions.xml', 'views/dss_maintains.xml', 'views/dss_provisionstypen.xml', 'views/dss_provision.xml', 'views/dss_zahlungen.xml', + 'views/dss_web_contracts.xml', + 'views/dss_invoices.xml', 'views/mainsystem_view.xml', + 'views/dss_importinvoicelist.xml', 'views/menu.xml', 'views/company_view.xml', 'views/google_map.xml', 'views/dss_report_invoice.xml', + 'data/ir_model_data.xml', ], 'demo': [], 'installable': True, @@ -51,14 +59,18 @@ 'web.assets_backend': [ 'DigitalSignage/static/src/img/*', 'DigitalSignage/static/src/xml/screenDesignerView.xml', + 'DigitalSignage/static/src/js/form_label.js', 'DigitalSignage/static/src/js/form_button.js', 'DigitalSignage/static/src/js/kanban_button.js', 'DigitalSignage/static/src/xml/form_button.xml', + 'DigitalSignage/static/src/js/dss_klistmanager.js', + 'DigitalSignage/static/src/xml/form_label.xml', ], 'web.assets_common': [ 'DigitalSignage/static/images/**/*', 'DigitalSignage/static/src/js/screenDesignerView.js', 'DigitalSignage/static/src/css/dss.css', + 'DigitalSignage/static/src/scss/style.scss', ], 'web.assets_qweb': [ ], diff --git a/__pycache__/__init__.cpython-311.pyc b/__pycache__/__init__.cpython-311.pyc index 3aa830b..27e1394 100644 Binary files a/__pycache__/__init__.cpython-311.pyc and b/__pycache__/__init__.cpython-311.pyc differ diff --git a/controllers/__pycache__/__init__.cpython-311.pyc b/controllers/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..20fe4d9 Binary files /dev/null and b/controllers/__pycache__/__init__.cpython-311.pyc differ diff --git a/controllers/__pycache__/main.cpython-311.pyc b/controllers/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000..28d7e95 Binary files /dev/null and b/controllers/__pycache__/main.cpython-311.pyc differ diff --git a/controllers/website_form.py b/controllers/website_form.py new file mode 100644 index 0000000..865d038 --- /dev/null +++ b/controllers/website_form.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import tools +from odoo.addons.phone_validation.tools import phone_validation +from odoo.addons.website.controllers import form +from odoo.http import request + +import logging +from odoo.http import request +_logger = logging.getLogger(__name__) + +class WebsiteForm(form.WebsiteForm): + + def _get_country(self): + visitor_partner = request.env['website.visitor']._get_visitor_from_request().partner_id + if visitor_partner: + # match same behaviour as in partner._phone_format() + country = visitor_partner.country_id or request.env.company.country_id + if country: + return country + country_code = request.geoip.get('country_code') + if country_code: + return request.env['res.country'].sudo().search([('code', '=', country_code)], limit=1) + return request.env['res.country'] + + def _get_phone_fields_to_validate(self): + return ['phone', 'mobile'] + + # Check and insert values from the form on the model + validation phone fields + def _handle_website_form(self, model_name, **kwargs): + _logger.info('Im Form Handling 0') + result = True + return result + + def insert_record(self, request, model, values, custom, meta=None): + _logger.info('Im Form Handling 1') + result = True + # super(WebsiteForm, self).insert_record(request, model, values, custom, meta=meta) + return result diff --git a/data/ir_model_data.xml b/data/ir_model_data.xml new file mode 100644 index 0000000..1f64227 --- /dev/null +++ b/data/ir_model_data.xml @@ -0,0 +1,31 @@ + + + + + create_contract + True + Vertragsdaten eingeben + + + + dss.web_contracts + + + + diff --git a/models/__init__.py b/models/__init__.py index e89e93e..e67a7ec 100755 --- a/models/__init__.py +++ b/models/__init__.py @@ -1,5 +1,8 @@ +from . import dss_activity_mixin +from . import dss_marker from . import dss_settings from . import dss_trigger +from . import dss_ads from . import dss_contract from . import dss_projects from . import dss_geraetetypen @@ -9,6 +12,7 @@ from . import dss_systems from . import dss_eventdays from . import dss_advertisefields from . import dss_trigger +from . import dss_triggerexecute from . import dss_triggervalues from . import dss_zahlungen from . import dss @@ -16,5 +20,8 @@ from . import dss_maintains from . import dss_provisionstypen from . import dss_provision from . import company +from . import dss_invoices +from . import dss_importinvoicelist +from . import dss_web_contracts diff --git a/models/__pycache__/__init__.cpython-311.pyc b/models/__pycache__/__init__.cpython-311.pyc index 574ca3c..2734bbf 100644 Binary files a/models/__pycache__/__init__.cpython-311.pyc and b/models/__pycache__/__init__.cpython-311.pyc differ diff --git a/models/__pycache__/company.cpython-311.pyc b/models/__pycache__/company.cpython-311.pyc index 0428b8a..a38e68d 100644 Binary files a/models/__pycache__/company.cpython-311.pyc and b/models/__pycache__/company.cpython-311.pyc differ diff --git a/models/__pycache__/dss.cpython-311.pyc b/models/__pycache__/dss.cpython-311.pyc index 922504d..d9e8294 100644 Binary files a/models/__pycache__/dss.cpython-311.pyc and b/models/__pycache__/dss.cpython-311.pyc differ diff --git a/models/__pycache__/dss_activity.cpython-311.pyc b/models/__pycache__/dss_activity.cpython-311.pyc new file mode 100644 index 0000000..c8bf1b7 Binary files /dev/null and b/models/__pycache__/dss_activity.cpython-311.pyc differ diff --git a/models/__pycache__/dss_activity_mixin.cpython-311.pyc b/models/__pycache__/dss_activity_mixin.cpython-311.pyc new file mode 100644 index 0000000..da0577d Binary files /dev/null and b/models/__pycache__/dss_activity_mixin.cpython-311.pyc differ diff --git a/models/__pycache__/dss_ads.cpython-311.pyc b/models/__pycache__/dss_ads.cpython-311.pyc new file mode 100644 index 0000000..a1bc0b3 Binary files /dev/null and b/models/__pycache__/dss_ads.cpython-311.pyc differ diff --git a/models/__pycache__/dss_advertisefields.cpython-311.pyc b/models/__pycache__/dss_advertisefields.cpython-311.pyc new file mode 100644 index 0000000..fbdce7d Binary files /dev/null and b/models/__pycache__/dss_advertisefields.cpython-311.pyc differ diff --git a/models/__pycache__/dss_contract.cpython-311.pyc b/models/__pycache__/dss_contract.cpython-311.pyc new file mode 100644 index 0000000..ef22ab9 Binary files /dev/null and b/models/__pycache__/dss_contract.cpython-311.pyc differ diff --git a/models/__pycache__/dss_eventdays.cpython-311.pyc b/models/__pycache__/dss_eventdays.cpython-311.pyc new file mode 100644 index 0000000..286b691 Binary files /dev/null and b/models/__pycache__/dss_eventdays.cpython-311.pyc differ diff --git a/models/__pycache__/dss_geraetetypen.cpython-311.pyc b/models/__pycache__/dss_geraetetypen.cpython-311.pyc new file mode 100644 index 0000000..f5f6ae8 Binary files /dev/null and b/models/__pycache__/dss_geraetetypen.cpython-311.pyc differ diff --git a/models/__pycache__/dss_importInvoicelist.cpython-311.pyc b/models/__pycache__/dss_importInvoicelist.cpython-311.pyc new file mode 100644 index 0000000..519437f Binary files /dev/null and b/models/__pycache__/dss_importInvoicelist.cpython-311.pyc differ diff --git a/models/__pycache__/dss_importinvoicelist.cpython-311.pyc b/models/__pycache__/dss_importinvoicelist.cpython-311.pyc new file mode 100644 index 0000000..9a0dc24 Binary files /dev/null and b/models/__pycache__/dss_importinvoicelist.cpython-311.pyc differ diff --git a/models/__pycache__/dss_invoices.cpython-311.pyc b/models/__pycache__/dss_invoices.cpython-311.pyc new file mode 100644 index 0000000..7134fa6 Binary files /dev/null and b/models/__pycache__/dss_invoices.cpython-311.pyc differ diff --git a/models/__pycache__/dss_maintains.cpython-311.pyc b/models/__pycache__/dss_maintains.cpython-311.pyc new file mode 100644 index 0000000..ab746db Binary files /dev/null and b/models/__pycache__/dss_maintains.cpython-311.pyc differ diff --git a/models/__pycache__/dss_marker.cpython-311.pyc b/models/__pycache__/dss_marker.cpython-311.pyc new file mode 100644 index 0000000..8b55ffa Binary files /dev/null and b/models/__pycache__/dss_marker.cpython-311.pyc differ diff --git a/models/__pycache__/dss_projects.cpython-311.pyc b/models/__pycache__/dss_projects.cpython-311.pyc new file mode 100644 index 0000000..7051196 Binary files /dev/null and b/models/__pycache__/dss_projects.cpython-311.pyc differ diff --git a/models/__pycache__/dss_provision.cpython-311.pyc b/models/__pycache__/dss_provision.cpython-311.pyc new file mode 100644 index 0000000..5f0fd0a Binary files /dev/null and b/models/__pycache__/dss_provision.cpython-311.pyc differ diff --git a/models/__pycache__/dss_provisionstypen.cpython-311.pyc b/models/__pycache__/dss_provisionstypen.cpython-311.pyc new file mode 100644 index 0000000..e195603 Binary files /dev/null and b/models/__pycache__/dss_provisionstypen.cpython-311.pyc differ diff --git a/models/__pycache__/dss_settings.cpython-311.pyc b/models/__pycache__/dss_settings.cpython-311.pyc new file mode 100644 index 0000000..f472b2f Binary files /dev/null and b/models/__pycache__/dss_settings.cpython-311.pyc differ diff --git a/models/__pycache__/dss_software.cpython-311.pyc b/models/__pycache__/dss_software.cpython-311.pyc new file mode 100644 index 0000000..0fbd7be Binary files /dev/null and b/models/__pycache__/dss_software.cpython-311.pyc differ diff --git a/models/__pycache__/dss_systems.cpython-311.pyc b/models/__pycache__/dss_systems.cpython-311.pyc new file mode 100644 index 0000000..ddb9597 Binary files /dev/null and b/models/__pycache__/dss_systems.cpython-311.pyc differ diff --git a/models/__pycache__/dss_systemtypen.cpython-311.pyc b/models/__pycache__/dss_systemtypen.cpython-311.pyc new file mode 100644 index 0000000..13eace5 Binary files /dev/null and b/models/__pycache__/dss_systemtypen.cpython-311.pyc differ diff --git a/models/__pycache__/dss_trigger.cpython-311.pyc b/models/__pycache__/dss_trigger.cpython-311.pyc new file mode 100644 index 0000000..4e93b90 Binary files /dev/null and b/models/__pycache__/dss_trigger.cpython-311.pyc differ diff --git a/models/__pycache__/dss_triggerexecute.cpython-311.pyc b/models/__pycache__/dss_triggerexecute.cpython-311.pyc new file mode 100644 index 0000000..6c696e1 Binary files /dev/null and b/models/__pycache__/dss_triggerexecute.cpython-311.pyc differ diff --git a/models/__pycache__/dss_triggervalues.cpython-311.pyc b/models/__pycache__/dss_triggervalues.cpython-311.pyc new file mode 100644 index 0000000..44dbfdc Binary files /dev/null and b/models/__pycache__/dss_triggervalues.cpython-311.pyc differ diff --git a/models/__pycache__/dss_web_contracts.cpython-311.pyc b/models/__pycache__/dss_web_contracts.cpython-311.pyc new file mode 100644 index 0000000..c006500 Binary files /dev/null and b/models/__pycache__/dss_web_contracts.cpython-311.pyc differ diff --git a/models/__pycache__/dss_zahlungen.cpython-311.pyc b/models/__pycache__/dss_zahlungen.cpython-311.pyc new file mode 100644 index 0000000..a7811c6 Binary files /dev/null and b/models/__pycache__/dss_zahlungen.cpython-311.pyc differ diff --git a/models/company.py b/models/company.py index 4b77965..b573bd8 100755 --- a/models/company.py +++ b/models/company.py @@ -20,8 +20,8 @@ class ResCompany(models.Model): dsspartner_vertrag = fields.Boolean('Aquisepartner', default=False) dsspartner_eigenwerbung = fields.Boolean('Eigenwerbekunde ', default=False) dsspartner_sonstiges = fields.Boolean('Sonstiges', default=False) - dsspartner_sonstiges_text = fields.Char('Sonstiges', default=False) - dssprojekte = fields.Many2many('dss.main', readonly=1 ) + dsspartner_sonstiges_text = fields.Char('Sonstiges Text', default=False) + dssprojekte = fields.Many2many('dss.projects', readonly=1 ) dsspartner_name = fields.Char('Kundenname', default=False) dsspartner_vorname = fields.Char('KundenVorname', default=False) dssinternpartner = fields.Boolean('Mitarbeiter', default=False) diff --git a/models/dss.py b/models/dss.py index be74037..7ce9f6d 100755 --- a/models/dss.py +++ b/models/dss.py @@ -50,6 +50,7 @@ def _generate_preview_from_binary_2(self, videofile_file): class dssimport(models.Model): _name = "dss.import" _description = "DigitalSignage Import" + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') importfilename = fields.Binary('Import Dateiname') importtext = fields.Text('Import Verlauf') @@ -93,6 +94,10 @@ class dsscontractstatus(models.Model): color = fields.Char(string='Color Index') icon = fields.Image() order = fields.Integer('Reihenfolge') + systemtypdefault = fields.Boolean(string='Default Typ',tracking=True) + systemtyp = fields.Many2one('dss.systemtypen',tracking=True) + systemtypuuid = fields.Char(related='systemtyp.uuid',tracking=True) + kanban_display_minimal = fields.Boolean(string='Kanban minimalisiert') @api.model def _default_uuid(self): @@ -309,7 +314,7 @@ class dssscreendesign(models.Model): user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user()) user_lastedit = fields.Char('Änderungsuser') - screenname = fields.Char('Bildschirmname',track_visibility='onchange',tracking=True) + screenname = fields.Char('Bildschirmname',tracking=True) fields = fields.One2many('dss.advertisefields','display',string='Werbefelder',tracking=True) @api.model @@ -326,704 +331,3 @@ class dssscreendesign(models.Model): def get_data(self): outlist = {'uuid' : 2222} return outlist - -class dsscontractads(models.Model): - - def _default_work_state(self): - ds = self.env['dss.workstate'].search([('statusname', '=', 'Neu')], limit=1).id - _logger.debug(ds) - return ds - - def _default_work_state_color(self): - ds = self.env['dss.workstate'].search([('statusname', '=', 'Neu')], limit=1).color - _logger.info(ds) - return ds - - def _default_todo_state(self): - ds = self.env['dss.todostate'].search([('statusnr', '=', '0')], limit=1).id - if not ds: ds = 1 - _logger.debug(ds) - # ds = - return ds - - @api.model - def create(self, vals): - result = super().create(vals) - resstr = result.uuid - _logger.info(resstr) - for n_record in result: - resstr = n_record.uuid - _logger.info(resstr) - n_record.date_create = date.today() - n_record.user_create = self.env.user.name - allads = n_record.contract.ads - _logger.info(allads) - if allads != False: - for ad in allads: - ad.ad_is_lastpos = False - n_record.ad_is_lastpos = True - contract = n_record.contract - contract.ads_last_ad = n_record - return result - - # @api.depends('need_media') - # def _getmedialist(self): - # mlist = [] - # mlist = self.env['dss.mediarelations'].search([('ad','=',self.id)]) - # if mlist != False: - # _logger.info('AD Need_Medias A_'+str(self)+' - Computed Medias '+str(mlist)) - # self.need_media = mlist.ids - # else: - # self.need_media = False - - _name = "dss.ads" - _description = "DigitalSignage Werbekampagnen Phasen" - _inherit = ['mail.thread', 'mail.activity.mixin'] - # _inherit = ['mail.activity.mixin'] - # 'mail.thread','mail.activity.mixin' - _rec_name = "adname" - # _inherit = ['mail.thread', 'mail.activity.mixin'] - uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, - string='UUID') - aduuid = fields.Char(related='uuid') - - date_create = fields.Date('Erstellungsdatum', default=lambda self: self._default_create_date()) - date_lastedit = fields.Date('Änderungsdatum') - user_create = fields.Char('Erstellungsuser', default=lambda self: self._default_create_user()) - user_lastedit = fields.Char('Änderungsuser') - # uuid = fields.Char('UUID', required=True, translate=True) - adname = fields.Char('Kampagnenname', required=True, tracking=True) - adtype = fields.Selection( - [('MAIN', 'Ersteinrichtung'), ('KCHN', 'Änderung durch Kunde'), ('LCHN', 'Änderung durch Logumedia'), - ('SONS', 'Sonstige Änderung')], tracking=True) - adpos = fields.Integer('Reihenfolge', default=lambda self: self._default_adpos(), - tracking=True) - ad_is_lastpos = fields.Boolean('Letzte Aktion', tracking=True) - - start_date = fields.Date('gew. Ausstrahl.Begin', tracking=True) - end_date = fields.Date('gew. Ausstrahl.Ende', tracking=True) - - contract = fields.Many2one('dss.contracts', store=True, tracking=True) - contract_id = fields.Char(related='contract.contract_id') - contract_name = fields.Char(related='contract.contract_name') - contract_need_media = fields.Many2many(related='contract.need_media', tracking=True) - - project = fields.Many2one('dss.projects', string='Project', store=True, tracking=True) - project_id = fields.Integer(related='project.projectid', string='Project ID') - - parent_ad = fields.Many2one('dss.ads', string='UrsprungsWerbung', store=True) - parent_ad_uuid = fields.Char(related='parent_ad.uuid') - description = fields.Text('Beschreibung') - amount = fields.Float('Extrakosten', tracking=True) - order = fields.Integer('Reihenfolge', tracking=True) - - # need_media = fields.Many2many('dss.mediarelations','ad',string='Medien') - need_media = fields.One2many('dss.mediarelations', 'ad', string='Medien') - - work_state = fields.Many2one('dss.workstate', default=_default_work_state, tracking=True) - work_state_color = fields.Char(related='work_state.color') - work_state_text = fields.Char(related='work_state.statusname') - work_state_info = fields.Char('Zusatzinfo') - - ad_state = fields.Many2one('dss.adstate', tracking=True) - ad_state_color = fields.Char(related='ad_state.color') - ad_state_text = fields.Char(related='ad_state.statusname') - ad_state_func = fields.Selection(related='ad_state.func') - - todo_state = fields.Many2one('dss.todostate', default=_default_todo_state, - tracking=True) - todo_state_color = fields.Char(related='todo_state.color') - todo_state_text = fields.Char(related='todo_state.statusname') - todo_state_info = fields.Char('Zusatzinfo', tracking=True) - todo_state_until = fields.Date('Abarbeiten bis', tracking=True) - - cloud_add_directory = fields.Char('Cloud KundenKampagnen Ordner', tracking=True) - - date_zuarbeit = fields.Date(string='Zuarbeit Datum', help='Zuarbeit gesendet am', tracking=True) - date_korrekturabzug = fields.Date(string='K.Abzug Datum', help='Korrekturabzug gesendet am') - date_korrekturfreigabe = fields.Date(string='K.Freigabe Datum', help='Korrekturfreigabe erhalten am', - tracking=True) - date_korrekturfreigabe_frist = fields.Date(string='K.Freigabe bis Datum', help='Korrekturfreigabe sollte bis .... erfolgen') - freigabe_durch_ablauf = fields.Boolean(string='Zeitablauf',help='Freigabe wurde durch Zeitablauf erreicht ?', tracking=True) - - @api.model - def _default_uuid(self): - return str(uuid.uuid4()) - - def _default_create_date(self): - return str(date.today()) - - def _default_create_user(self): - return str(self.env.user.name) - - def _default_adpos(self): - pos = self.env['dss.ads'].search_count([('contract_id', '=', self.contract.id)]) + 1 - return str(pos) - - @api.onchange('ad_state') - def _onchange_ad_state(self): - for record in self: - if record.ad_is_lastpos == True: - contract = record.contract - contract.ads_last_state = record.ad_state - # mtyp = self.env['dss.adstructures'].search([("uuid","=",str(record.mediastructure.uuid))]) - # buildmediarelations(self) - self.date_lastedit = str(date.today()) - - # self.mediastructure = mtyp - - def pyaction_view_ad_details(self): - action = self.env['ir.actions.act_window'].with_context({'default_adid': self.id})._for_xml_id( - 'DigitalSignage.action_dss_ads_view') - # action['display_name'] = self.ad_name - # action['domain'] = '[["projectid","=","4"]]' - # context = action['context'].replace('', str(self.id)) - # context = ast.literal_eval(context) - # context.update({ - # 'create': self.active, - # 'active_test': self.active - # }) - # action['context'] = context - return { - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form,tree', - 'res_model': 'dss.ads', - 'target': 'current', - 'context': '', - 'res_id': self.id, - 'display_name': ' ' + self.adname, - 'domain': '' - } - - return action - - def pydoviewallads(self): - action = self.env['ir.actions.act_window'].with_context({'default_adid': self.id})._for_xml_id( - 'DigitalSignage.act_dss_ads_view_full') - action['display_name'] = self.contract_name - # action['domain'] = '[["projectid","=","4"]]' - # context = action['context'].replace('', str(self.id)) - # context = ast.literal_eval(context) - # context.update({ - # 'create': self.active, - # 'active_test': self.active - # }) - # action['context'] = context - # return { - # 'type': 'ir.actions.act_window', - # 'view_type':'form', - # 'view_mode':'form,tree', - # 'res_model':'dss.ads', - # 'target':'current', - # 'context':'', - # 'res_id':kampagne.id, - # 'display_name' : 'Werbekampagne '+kampagne.adname, - # 'domain':'[("contract","=","context[active_id]")]' - # } - # return action - return { - 'type': 'ir.actions.act_window', - 'view_type': 'kanban', - 'view_mode': 'kanban', - 'res_model': 'dss.ads', - 'target': 'current', - 'context': '{"group_by":["parent_ad"]}', - # 'res_id':self.parent_ad, - 'display_name': 'Übersicht für ' + self.adname, - 'domain': [("contract", "=", self.contract.id)] - } - - def pydonewad(self): - for n_record in self: - resstr = n_record.uuid - _logger.info(resstr) - allads = n_record.contract.ads - _logger.info(allads) - abort = False - if allads != False: - for ad in allads: - if ad.ad_state.func != 'FIN': - abort = True - if abort == False: - defadstate = self.env['dss.adstate'].search([('func', '=', 'STD')], limit=1).id - if not defadstate: - defadstate = 1 - if self.ad_state.func == 'STD': - parent_id = self.id - else: - parent_id = self.parent_ad.id - newkampagne = self.env['dss.ads'].create({'contract': self.contract.id, 'project': self.project.id, - 'adname': 'AD_' + self.contract.contract_auto_name + ' ' + str( - date.today()), 'parent_ad': parent_id, 'adtype': 'KCHN', - 'ad_state': defadstate}) - _logger.info('C_' + str(self.id) + ' Kampagne erzeugt : ' + str(newkampagne)) - _logger.info('Prüfe Medien : C_' + str(self.id) + 'K_' + str(newkampagne.id)) - - mediaids = [] - for feld in self.contract.werbe_feld_selected: - for media in feld.mediastructure.medias: - if not media: - _logger.info('Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( - newkampagne.id) + ' Kein Medium in MedienStructur von F_' + str(feld.id) + 'M_' + str( - media.id)) - else: - newmedia = self.env['dss.mediarelations'].create( - {'field': feld.id, 'contract': self.contract.id, 'project': self.project.id, - 'field_uuid': feld.uuid, 'ad': newkampagne.id, 'relname': media.medianame, - 'mediatype': media.id}) - _logger.info('Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( - newkampagne.id) + ' setze Vertrag für Medium : ' + str(newmedia.contract) + '/' + str( - newmedia.ad)) - mediaids.append(newmedia.id) - newkampagne.write({'need_media': [(6, 0, mediaids)]}) - _logger.info('Click auf Werbekampagne : C_' + str(self.contract.id) + 'A_' + str( - newkampagne.id) + ' setze Media ') - - return { - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form,tree', - 'res_model': 'dss.ads', - 'target': 'current', - 'context': '', - 'res_id': newkampagne.id, - 'display_name': 'Änderung zur Werbekampagne ' + newkampagne.parent_ad.adname, - 'domain': '[("id","=","context[newkampagne.id]")]' - } - else: - raise ValidationError( - _("Kann neue Aktualisierung erst anlegen wenn alle vorherigen Schritte beendet wurden !")) - - def setStandardText(self, tid): - text = self.env['dss.texts'].search([('text_id', '=', tid)], limit=1) - if text: - self.write({'description': text.description}) - - -class dsscontractads(models.Model): - - def _default_work_state(self): - ds = self.env['dss.workstate'].search([('statusname', '=', 'Neu')], limit=1).id - _logger.debug(ds) - return ds - - def _default_work_state_color(self): - ds = self.env['dss.workstate'].search([('statusname', '=', 'Neu')], limit=1).color - _logger.info(ds) - return ds - - def _default_todo_state(self): - ds = self.env['dss.todostate'].search([('statusnr', '=', '0')], limit=1).id - if not ds: ds = 1 - _logger.debug(ds) - # ds = - return ds - - @api.model - def create(self, vals): - result = super().create(vals) - resstr = result.uuid - _logger.info(resstr) - for n_record in result: - resstr = n_record.uuid - _logger.info(resstr) - n_record.date_create = date.today() - n_record.user_create = self.env.user.name - allads = n_record.contract.ads - _logger.info(allads) - if allads != False: - for ad in allads: - ad.ad_is_lastpos = False - n_record.ad_is_lastpos = True - contract = n_record.contract - contract.ads_last_ad = n_record - return result - - # @api.depends('need_media') - # def _getmedialist(self): - # mlist = [] - # mlist = self.env['dss.mediarelations'].search([('ad','=',self.id)]) - # if mlist != False: - # _logger.info('AD Need_Medias A_'+str(self)+' - Computed Medias '+str(mlist)) - # self.need_media = mlist.ids - # else: - # self.need_media = False - - _name = "dss.ads" - _description = "DigitalSignage Werbekampagnen" - _inherit = ['mail.thread', 'mail.activity.mixin','dss.triggermodel'] - # _inherit = ['mail.activity.mixin'] - # 'mail.thread','mail.activity.mixin' - _rec_name = "adname" - # _inherit = ['mail.thread', 'mail.activity.mixin'] - uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, - string='UUID') - aduuid = fields.Char(related='uuid') - - date_create = fields.Date('Erstellungsdatum', default=lambda self: self._default_create_date()) - date_lastedit = fields.Date('Änderungsdatum') - user_create = fields.Char('Erstellungsuser', default=lambda self: self._default_create_user()) - user_lastedit = fields.Char('Änderungsuser') - # uuid = fields.Char('UUID', required=True, translate=True) - adname = fields.Char('Kampagnenname', required=True, tracking=True) - adtype = fields.Selection( - [('MAIN', 'Ersteinrichtung'), ('KCHN', 'Änderung durch Kunde'), ('LCHN', 'Änderung durch Logumedia'), - ('SONS', 'Sonstige Änderung'),('PREA', 'Vorausplanung')], tracking=True) - adpos = fields.Integer('Reihenfolge', default=lambda self: self._default_adpos(), - tracking=True) - ad_is_lastpos = fields.Boolean('Letzte Aktion', tracking=True) - - contract = fields.Many2one('dss.contracts', store=True, tracking=True) - contract_id = fields.Char(related='contract.contract_id') - contract_name = fields.Char(related='contract.contract_name') - contract_need_media = fields.Many2many(related='contract.need_media', tracking=True) - - project = fields.Many2one('dss.projects', string='Project', store=True, tracking=True) - project_id = fields.Integer(related='project.projectid', string='Project ID') - - parent_ad = fields.Many2one('dss.ads', string='UrsprungsWerbung', store=True) - parent_ad_uuid = fields.Char(related='parent_ad.uuid') - description = fields.Text('Beschreibung', tracking=True) - amount = fields.Float('Extrakosten', tracking=True) - order = fields.Integer('Reihenfolge', tracking=True) - - # need_media = fields.Many2many('dss.mediarelations','ad',string='Medien') - need_media = fields.One2many('dss.mediarelations', 'ad', string='Medien', tracking=True) - - work_state = fields.Many2one('dss.workstate', default=_default_work_state, tracking=True) - work_state_color = fields.Char(related='work_state.color') - work_state_text = fields.Char(related='work_state.statusname') - work_state_info = fields.Char('Zusatzinfo',tracking=True) - - ad_state = fields.Many2one('dss.adstate', tracking=True) - ad_state_color = fields.Char(related='ad_state.color') - ad_state_text = fields.Char(related='ad_state.statusname') - ad_state_func = fields.Selection(related='ad_state.func') - - todo_state = fields.Many2one('dss.todostate', default=_default_todo_state, - tracking=True) - todo_state_color = fields.Char(related='todo_state.color') - todo_state_text = fields.Char(related='todo_state.statusname') - todo_state_info = fields.Char('Zusatzinfo', tracking=True) - todo_state_until = fields.Date('Abarbeiten bis', tracking=True) - - cloud_add_directory = fields.Char('Cloud KundenKampagnen Ordner', tracking=True) - - date_zuarbeit = fields.Date(string='Zuarbeit Datum', help='Zuarbeit gesendet am', - tracking=True) - date_korrekturabzug = fields.Date(string='K.Abzug Datum', help='Korrekturabzug gesendet am', - tracking=True) - date_korrekturfreigabe = fields.Date(string='K.Freigabe Datum', help='Korrekturfreigabe erhalten am', - tracking=True) - date_korrekturfreigabe_ablauf = fields.Date(string='K.Freigabe Ablaufdatum', help='Korrekturfreigabe muss bis xxxx erfolgen.. sonst Autofreigabe', - tracking=True) - date_korrekturfreigabe_ablauf_compute = fields.Char(compute='_date_korrekturfreigabe_ablauf_compute') - date_korrekturfreigabe_ablauf_compute_int = fields.Integer(compute='_date_korrekturfreigabe_ablauf_compute_int') - korrekturfreigabe_ablauf_erfolgt = fields.Boolean(string='K.Freigabe durch Ablauf', help='Korrekturfreigabe erfolgte durch Zeitablauf ?', - tracking=True) - date_start_planed = fields.Date(string='geplantes Startdatum', tracking=True) - date_start_planed_calendar_event=fields.Integer('gepl. Start - Kal.ID',tracking=True) - date_start_real = fields.Date(string='wirkliches Startdatum', tracking=True) - - date_remove_planed = fields.Date(string='geplantes Enddatum', tracking=True) - date_remove_real = fields.Date(string='wirkliches Enddatum', tracking=True) - - @api.depends('date_korrekturfreigabe_ablauf') - def _date_korrekturfreigabe_ablauf_compute(self): - self.date_korrekturfreigabe_ablauf_compute = '' - if not self: - return '' - pass - else: - for record in self: - if not record: - return '' - pass - else: - if not record.date_korrekturfreigabe_ablauf: - return '' - pass - else: - datedif = record.date_korrekturfreigabe_ablauf-date.today() - record.date_korrekturfreigabe_ablauf_compute='Noch '+str(datedif.days)+' Tage bis Autoablauf' - - @api.depends('date_korrekturfreigabe_ablauf') - def _date_korrekturfreigabe_ablauf_compute_int(self): - for record in self: - if record: - if record.date_korrekturfreigabe_ablauf: - datedif = record.date_korrekturfreigabe_ablauf-date.today() - record.date_korrekturfreigabe_ablauf_compute_int = datedif.days - - def _check_date_korrekturfreigabe_ablauf(self): - for record in self: - if record: - if record.date_korrekturfreigabe_ablauf: - datedif = record.date_korrekturfreigabe_ablauf-date.today() - _logger.info('Contract Autokorrektur Running C_' + str(record.contract)+' / '+str(datedif)) - if (datedif.days<=0) & ( not record.date_korrekturfreigabe): - _logger.info('Contract Autokorrektur Running C_' + str(record.contract)+' A_'+str(record)+' Set Values') - record.date_korrekturfreigabe = date.today() - record.korrekturfreigabe_ablauf_erfolgt = True - body = 'Für die Werbekampagne '+str(record.adname)+' im Vertrag '+str(record.contract.contract_auto_name)+' des Projektes '+str(record.project.projektname)+' wurde der Korekturabzug automatisch durch Zeitablauf bestätigt !' - record.message_post(body=body) - self.env['mail.message'].create({'message_type': 'comment','subtype_id': self.env.ref('mail.mt_comment').id, - 'model': 'mail.channel','res_id': self.env.ref('mail.channel_all_employees').id,'body': body,}) - - @api.model - def _default_uuid(self): - return str(uuid.uuid4()) - - def _default_create_date(self): - return str(date.today()) - - def _default_create_user(self): - return str(self.env.user.name) - - def _default_adpos(self): - pos = self.env['dss.ads'].search_count([('contract_id', '=', self.contract.id)]) + 1 - return str(pos) - - @api.onchange('ad_state') - def _onchange_ad_state(self): - for record in self: - if record.ad_is_lastpos == True: - contract = record.contract - contract.ads_last_state = record.ad_state - # mtyp = self.env['dss.adstructures'].search([("uuid","=",str(record.mediastructure.uuid))]) - # buildmediarelations(self) - self.date_lastedit = str(date.today()) - - # self.mediastructure = mtyp - - @api.onchange('date_korrekturabzug') - def _date_korrekturabzug_change(self): - for record in self: - autodays=0 - if record.date_korrekturabzug: - autodays=self.env['dss.settings'].search([],limit=1).freigabe_auto_time - record.date_korrekturfreigabe_ablauf = record.date_korrekturabzug + relativedelta(days=autodays) - - def pyaction_view_ad_details(self): - action = self.env['ir.actions.act_window'].with_context({'default_adid': self.id})._for_xml_id( - 'DigitalSignage.action_dss_ads_view') - # action['display_name'] = self.ad_name - # action['domain'] = '[["projectid","=","4"]]' - # context = action['context'].replace('', str(self.id)) - # context = ast.literal_eval(context) - # context.update({ - # 'create': self.active, - # 'active_test': self.active - # }) - # action['context'] = context - return { - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form,tree', - 'res_model': 'dss.ads', - 'target': 'current', - 'context': '', - 'res_id': self.id, - 'display_name': ' ' + self.adname, - 'domain': '' - } - - return action - - def pydoviewallads(self): - action = self.env['ir.actions.act_window'].with_context({'default_adid': self.id})._for_xml_id( - 'DigitalSignage.act_dss_ads_view_full') - action['display_name'] = self.contract_name - # action['domain'] = '[["projectid","=","4"]]' - # context = action['context'].replace('', str(self.id)) - # context = ast.literal_eval(context) - # context.update({ - # 'create': self.active, - # 'active_test': self.active - # }) - # action['context'] = context - # return { - # 'type': 'ir.actions.act_window', - # 'view_type':'form', - # 'view_mode':'form,tree', - # 'res_model':'dss.ads', - # 'target':'current', - # 'context':'', - # 'res_id':kampagne.id, - # 'display_name' : 'Werbekampagne '+kampagne.adname, - # 'domain':'[("contract","=","context[active_id]")]' - # } - # return action - return { - 'type': 'ir.actions.act_window', - 'view_type': 'kanban', - 'view_mode': 'kanban', - 'res_model': 'dss.ads', - 'target': 'current', - 'context': '{"group_by":["parent_ad"]}', - # 'res_id':self.parent_ad, - 'display_name': 'Übersicht für ' + self.adname, - 'domain': [("contract", "=", self.contract.id)] - } - - def pydonewpread(self): - defadstate = self.env['dss.adstate'].search([('func', '=', 'STD')], limit=1).id - if not defadstate: - defadstate = 1 - if self.ad_state.func == 'STD': - parent_id = self.id - else: - parent_id = self.parent_ad.id - newkampagne = self.env['dss.ads'].create({'contract': self.contract.id, 'project': self.project.id, - 'adname': 'PRE_' + self.contract.contract_auto_name + ' ' + str( - date.today()), 'parent_ad': parent_id, 'adtype': 'PREA', - 'ad_state': defadstate}) - _logger.info('C_' + str(self.id) + ' Kampagne erzeugt : ' + str(newkampagne)) - _logger.info('Erzeugte PreWerbekampagne - Prüfe Medien : C_' + str(self.id) + 'K_' + str(newkampagne.id)) - - mediaids = [] - for feld in self.contract.werbe_feld_selected: - for media in feld.mediastructure.medias: - if not media: - _logger.info('Erzeugte PreWerbekampagne - Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( - newkampagne.id) + ' Kein Medium in MedienStructur von F_' + str(feld.id) + 'M_' + str( - media.id)) - else: - newmedia = self.env['dss.mediarelations'].create( - {'field': feld.id, 'contract': self.contract.id, 'project': self.project.id, - 'field_uuid': feld.uuid, 'ad': newkampagne.id, 'relname': media.medianame, - 'mediatype': media.id}) - _logger.info('Erzeugte PreWerbekampagne - Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( - newkampagne.id) + ' setze Vertrag für Medium : ' + str(newmedia.contract) + '/' + str( - newmedia.ad)) - mediaids.append(newmedia.id) - newkampagne.write({'need_media': [(6, 0, mediaids)]}) - _logger.info('Erzeugte PreWerbekampagne : C_' + str(self.contract.id) + 'A_' + str( - newkampagne.id) + ' setze Media ') - return { - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form,tree', - 'res_model': 'dss.ads', - 'target': 'current', - 'context': '', - 'res_id': newkampagne.id, - 'display_name': 'Änderung zur Werbekampagne ' + newkampagne.parent_ad.adname, - 'domain': '[("id","=","context[newkampagne.id]")]' - } - - def pydonewad(self): - for n_record in self: - resstr = n_record.uuid - _logger.info(resstr) - allads = n_record.contract.ads - _logger.info(allads) - abort = False - if allads != False: - for ad in allads: - if ad.ad_state.func != 'FIN': - if ad.adtype !='PREA': - abort = True - if abort == False: - defadstate = self.env['dss.adstate'].search([('func', '=', 'STD')], limit=1).id - if not defadstate: - defadstate = 1 - if self.ad_state.func == 'STD': - parent_id = self.id - else: - parent_id = self.parent_ad.id - newkampagne = self.env['dss.ads'].create({'contract': self.contract.id, 'project': self.project.id, - 'adname': 'AD_' + self.contract.contract_auto_name + ' ' + str( - date.today()), 'parent_ad': parent_id, 'adtype': 'KCHN', - 'ad_state': defadstate}) - _logger.info('C_' + str(self.id) + ' Kampagne erzeugt : ' + str(newkampagne)) - _logger.info('Prüfe Medien : C_' + str(self.id) + 'K_' + str(newkampagne.id)) - - mediaids = [] - for feld in self.contract.werbe_feld_selected: - for media in feld.mediastructure.medias: - if not media: - _logger.info('Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( - newkampagne.id) + ' Kein Medium in MedienStructur von F_' + str(feld.id) + 'M_' + str( - media.id)) - else: - newmedia = self.env['dss.mediarelations'].create( - {'field': feld.id, 'contract': self.contract.id, 'project': self.project.id, - 'field_uuid': feld.uuid, 'ad': newkampagne.id, 'relname': media.medianame, - 'mediatype': media.id}) - _logger.info('Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( - newkampagne.id) + ' setze Vertrag für Medium : ' + str(newmedia.contract) + '/' + str( - newmedia.ad)) - mediaids.append(newmedia.id) - newkampagne.write({'need_media': [(6, 0, mediaids)]}) - _logger.info('Click auf Werbekampagne : C_' + str(self.contract.id) + 'A_' + str( - newkampagne.id) + ' setze Media ') - - return { - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form,tree', - 'res_model': 'dss.ads', - 'target': 'current', - 'context': '', - 'res_id': newkampagne.id, - 'display_name': 'Änderung zur Werbekampagne ' + newkampagne.parent_ad.adname, - 'domain': '[("id","=","context[newkampagne.id]")]' - } - else: - raise ValidationError( - _("Kann neue Aktualisierung erst anlegen wenn alle vorherigen Schritte beendet wurden !")) - def pydoprecopyad(selfself): - for n_record in self: - resstr = n_record.uuid - _logger.info(resstr) - allads = n_record.contract.ads - _logger.info(allads) - abort = False - if allads != False: - for ad in allads: - if ad.ad_state.func != 'FIN': - if ad.adtype != 'PREA': - abort = True - if abort == False: - - return { - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form,tree', - 'res_model': 'dss.ads', - 'target': 'current', - 'context': '', - 'res_id': newkampagne.id, - 'display_name': 'Änderung zur Werbekampagne ' + newkampagne.parent_ad.adname, - 'domain': '[("id","=","context[newkampagne.id]")]' - } - - else: - raise ValidationError( - _("Kann neue Aktualisierung erst anlegen wenn alle vorherigen Schritte beendet wurden !")) - - def setStandardText(self, tid): - text = self.env['dss.texts'].search([('text_id', '=', tid)], limit=1) - if text: - self.write({'description': text.description}) - - def pyaddstartdate(self): - self.env['calendar.event'].search([('id','=',self.date_start_planed_calendar_event)]).unlink() - event = { - 'start': self.date_start_planed.strftime('%Y-%m-%d %H:%M:%S'), - 'stop': self.date_start_planed.strftime('%Y-%m-%d %H:%M:%S'), - 'duration': 24, - 'allday': True, - 'partner_ids': (4,self.env['dss.settings'].search([],limit=1).contact_runtime_user.partner_id.id), - 'name': 'Geplanter Start '+self.contract.contract_auto_name, - 'description': 'Geplanter Start '+self.contract.contract_auto_name+' im Projekt '+self.project.projektname, - 'user_id': self.env['dss.settings'].search([],limit=1).contact_runtime_user.id - } - _logger.debug('linking new Startevent ' + str(event) + ' ' + str(self.uuid)) - self.date_start_planed_calendar_event=self.env['calendar.event'].create(event).id - return "" - - def pyaddenddate(self): - return 1 diff --git a/models/dss_activity_mixin.py b/models/dss_activity_mixin.py new file mode 100644 index 0000000..69e2f0a --- /dev/null +++ b/models/dss_activity_mixin.py @@ -0,0 +1,33 @@ +import uuid +import logging +import datetime + +from odoo import api, fields, models, _ +from odoo import tools +from datetime import datetime +from datetime import date +from odoo.exceptions import ValidationError +from dateutil.relativedelta import relativedelta +import sys + +_logger = logging.getLogger(__name__) + +class dssActivityMixin(models.Model): + _name = 'dss.activity.mixin' + _inherit = 'mail.activity.mixin' + _description = 'DigitalSignage Activity Inherit' + + def activity_schedule(self, act_type_xmlid='', date_deadline=None, summary='', note='', **act_values): + _logger.info("This is my activity debug message ! - schedule") + res = super(dssActivityMixin, self).activity_schedule(self, act_type_xmlid='', date_deadline=date_deadline, summary='', note='', **act_values) + return res + + def activity_feedback(self, act_type_xmlids, user_id=None, feedback=None, attachment_ids=None): + _logger.info("This is my activity debug message ! ") + res = super(dssActivityMixin, self).action_feedback(act_type_xmlids, user_id=user_id, feedback=feedback, attachment_ids=attachment_ids) + return res + + def activity_unlink(self, act_type_xmlids, user_id=None): + _logger.info("This is my activity debug message ! unlink ") + res = super(dssActivityMixin, self).activity_unlink(act_type_xmlids, user_id=user_id) + return res diff --git a/models/dss_ads.py b/models/dss_ads.py new file mode 100644 index 0000000..e00e2a9 --- /dev/null +++ b/models/dss_ads.py @@ -0,0 +1,464 @@ +# -*- coding: utf-8 -* + +# Test +# Test2 + +import ast +import datetime +import json +import re +import uuid +import logging +import base64 +import subprocess +import tempfile +import easywebdav +import os +import os.path + + +from odoo import api, fields, models, _ +from odoo import tools +from . import dss_settings +from odoo.exceptions import ValidationError +from datetime import date +from datetime import datetime +from dateutil.relativedelta import relativedelta +from pyffmpeg import FFmpeg +from tuya_iot import TuyaOpenAPI, TUYA_LOGGER +from tuya_connector import TuyaOpenAPI, TUYA_LOGGER +import sys + +TUYA_LOGGER.setLevel(logging.DEBUG) +_logger = logging.getLogger(__name__) + +class dsscontractads(models.Model): + + def _default_work_state(self): + ds = self.env['dss.workstate'].search([('statusname', '=', 'Neu')], limit=1).id + _logger.debug(ds) + return ds + + def _default_work_state_color(self): + ds = self.env['dss.workstate'].search([('statusname', '=', 'Neu')], limit=1).color + _logger.info(ds) + return ds + + def _default_todo_state(self): + ds = self.env['dss.todostate'].search([('statusnr', '=', '0')], limit=1).id + if not ds: ds = 1 + _logger.debug(ds) + # ds = + return ds + + @api.model + def create(self, vals): + result = super().create(vals) + resstr = result.uuid + _logger.info(resstr) + for n_record in result: + resstr = n_record.uuid + _logger.info(resstr) + n_record.date_create = date.today() + n_record.user_create = self.env.user.name + allads = n_record.contract.ads + _logger.info(allads) + if allads != False: + for ad in allads: + ad.ad_is_lastpos = False + n_record.ad_is_lastpos = True + contract = n_record.contract + contract.ads_last_ad = n_record + return result + + # @api.depends('need_media') + # def _getmedialist(self): + # mlist = [] + # mlist = self.env['dss.mediarelations'].search([('ad','=',self.id)]) + # if mlist != False: + # _logger.info('AD Need_Medias A_'+str(self)+' - Computed Medias '+str(mlist)) + # self.need_media = mlist.ids + # else: + # self.need_media = False + + _name = "dss.ads" + _description = "DigitalSignage Werbekampagnen" + _inherit = ['mail.thread', 'mail.activity.mixin','dss.triggermodel'] + # _inherit = ['mail.activity.mixin'] + # 'mail.thread','mail.activity.mixin' + _rec_name = "adname" + # _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, + string='UUID') + aduuid = fields.Char(related='uuid') + + date_create = fields.Date('Erstellungsdatum', default=lambda self: self._default_create_date()) + date_lastedit = fields.Date('Änderungsdatum') + user_create = fields.Char('Erstellungsuser', default=lambda self: self._default_create_user()) + user_lastedit = fields.Char('Änderungsuser') + # uuid = fields.Char('UUID', required=True, translate=True) + adname = fields.Char('Kampagnenname', required=True, tracking=True) + adtype = fields.Selection( + [('MAIN', 'Ersteinrichtung'), ('KCHN', 'Änderung durch Kunde'), ('LCHN', 'Änderung durch Logumedia'), + ('SONS', 'Sonstige Änderung'),('PREA', 'Vorausplanung')], tracking=True) + adpos = fields.Integer('Reihenfolge', default=lambda self: self._default_adpos(), + tracking=True) + ad_is_lastpos = fields.Boolean('Letzte Aktion', tracking=True) + + contract = fields.Many2one('dss.contracts', store=True, tracking=True) + contract_id = fields.Char(related='contract.contract_id') + contract_name = fields.Char(related='contract.contract_name') + contract_need_media = fields.Many2many(related='contract.need_media', string='Vertragsmedien', tracking=True) + + project = fields.Many2one('dss.projects', string='Project', store=True, tracking=True) + project_id = fields.Integer(related='project.projectid', string='Project ID') + + parent_ad = fields.Many2one('dss.ads', string='UrsprungsWerbung', store=True) + parent_ad_uuid = fields.Char(related='parent_ad.uuid') + description = fields.Text('Beschreibung', tracking=True) + amount = fields.Float('Extrakosten', tracking=True) + order = fields.Integer('Reihenfolge', tracking=True) + + # need_media = fields.Many2many('dss.mediarelations','ad',string='Medien') + need_media = fields.One2many('dss.mediarelations', 'ad', string='Medien', tracking=True) + + work_state = fields.Many2one('dss.workstate', default=_default_work_state, tracking=True) + work_state_color = fields.Char(related='work_state.color') + work_state_text = fields.Char(related='work_state.statusname') + work_state_info = fields.Char('Zusatzinfo',tracking=True) + + ad_state = fields.Many2one('dss.adstate', tracking=True) + ad_state_color = fields.Char(related='ad_state.color') + ad_state_text = fields.Char(related='ad_state.statusname') + ad_state_func = fields.Selection(related='ad_state.func') + + todo_state = fields.Many2one('dss.todostate', default=_default_todo_state, + tracking=True) + todo_state_color = fields.Char(related='todo_state.color') + todo_state_text = fields.Char(related='todo_state.statusname') + todo_state_info = fields.Char('Zusatzinfo', tracking=True) + todo_state_until = fields.Date('Abarbeiten bis', tracking=True) + + cloud_add_directory = fields.Char('Cloud KundenKampagnen Ordner', tracking=True) + + date_zuarbeit = fields.Date(string='Zuarbeit Datum', help='Zuarbeit gesendet am', + tracking=True) + date_korrekturabzug = fields.Date(string='K.Abzug Datum', help='Korrekturabzug gesendet am', + tracking=True) + date_korrekturfreigabe = fields.Date(string='K.Freigabe Datum', help='Korrekturfreigabe erhalten am', + tracking=True) + date_korrekturfreigabe_ablauf = fields.Date(string='K.Freigabe Ablaufdatum', help='Korrekturfreigabe muss bis xxxx erfolgen.. sonst Autofreigabe', + tracking=True) + date_korrekturfreigabe_ablauf_compute = fields.Char(compute='_date_korrekturfreigabe_ablauf_compute') + date_korrekturfreigabe_ablauf_compute_int = fields.Integer(compute='_date_korrekturfreigabe_ablauf_compute_int') + korrekturfreigabe_ablauf_erfolgt = fields.Boolean(string='K.Freigabe durch Ablauf', help='Korrekturfreigabe erfolgte durch Zeitablauf ?', + tracking=True) + korrekturfreigabe_ablauf_auto_cancel = fields.Boolean('Ablaufprüfung verhintern',tracking=True) + date_start_planed = fields.Date(string='geplantes Startdatum', tracking=True) + date_start_planed_calendar_event=fields.Integer('gepl. Start - Kal.ID',tracking=True) + date_start_real = fields.Date(string='wirkliches Startdatum', tracking=True) + date_start_real_mail_send_verbose = fields.Boolean(string='Startmail nicht versendet', tracking=True) + date_start_real_mail_send = fields.Boolean(string='Startmail versendet', tracking=True) + date_start_real_mail_data = fields.Date(string='Startmail versendet am', tracking=True) + + date_remove_planed = fields.Date(string='geplantes Enddatum', tracking=True) + date_remove_real = fields.Date(string='wirkliches Enddatum', tracking=True) + + @api.depends('date_korrekturfreigabe_ablauf') + def _date_korrekturfreigabe_ablauf_compute(self): + self.date_korrekturfreigabe_ablauf_compute = '' + if not self: + return '' + pass + else: + for record in self: + if not record: + return '' + pass + else: + if not record.date_korrekturfreigabe_ablauf: + return '' + pass + else: + datedif = record.date_korrekturfreigabe_ablauf-date.today() + record.date_korrekturfreigabe_ablauf_compute='Noch '+str(datedif.days)+' Tage bis Autoablauf' + + @api.depends('date_korrekturfreigabe_ablauf') + def _date_korrekturfreigabe_ablauf_compute_int(self): + for record in self: + if record: + if record.date_korrekturfreigabe_ablauf: + datedif = record.date_korrekturfreigabe_ablauf-date.today() + record.date_korrekturfreigabe_ablauf_compute_int = datedif.days + + def _check_date_korrekturfreigabe_ablauf(self): + for record in self: + if record: + if record.date_korrekturfreigabe_ablauf: + datedif = record.date_korrekturfreigabe_ablauf-date.today() + _logger.info('Contract Autokorrektur Running C_' + str(record.contract)+' / '+str(datedif)) + if (datedif.days<=0) & ( not record.date_korrekturfreigabe): + _logger.info('Contract Autokorrektur Running C_' + str(record.contract)+' A_'+str(record)+' Set Values') + record.date_korrekturfreigabe = date.today() + record.korrekturfreigabe_ablauf_erfolgt = True + body = 'Für die Werbekampagne '+str(record.adname)+' im Vertrag '+str(record.contract.contract_auto_name)+' des Projektes '+str(record.project.projektname)+' wurde der Korekturabzug automatisch durch Zeitablauf bestätigt !' + record.message_post(body=body) + self.env['mail.message'].create({'message_type': 'comment','subtype_id': self.env.ref('mail.mt_comment').id, + 'model': 'mail.channel','res_id': self.env.ref('mail.channel_all_employees').id,'body': body,}) + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + def _default_create_date(self): + return str(date.today()) + + def _default_create_user(self): + return str(self.env.user.name) + + def _default_adpos(self): + pos = self.env['dss.ads'].search_count([('contract_id', '=', self.contract.id)]) + 1 + return str(pos) + + @api.onchange('ad_state') + def _onchange_ad_state(self): + for record in self: + if record.ad_is_lastpos == True: + contract = record.contract + contract.ads_last_state = record.ad_state + # mtyp = self.env['dss.adstructures'].search([("uuid","=",str(record.mediastructure.uuid))]) + # buildmediarelations(self) + self.date_lastedit = str(date.today()) + + # self.mediastructure = mtyp + + @api.onchange('date_korrekturabzug') + def _date_korrekturabzug_change(self): + for record in self: + autodays=0 + if record.date_korrekturabzug: + autodays=self.env['dss.settings'].search([],limit=1).freigabe_auto_time + record.date_korrekturfreigabe_ablauf = record.date_korrekturabzug + relativedelta(days=autodays) + + def pyaction_view_ad_details(self): + action = self.env['ir.actions.act_window'].with_context({'default_adid': self.id})._for_xml_id( + 'DigitalSignage.action_dss_ads_view') + # action['display_name'] = self.ad_name + # action['domain'] = '[["projectid","=","4"]]' + # context = action['context'].replace('', str(self.id)) + # context = ast.literal_eval(context) + # context.update({ + # 'create': self.active, + # 'active_test': self.active + # }) + # action['context'] = context + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': 'dss.ads', + 'target': 'current', + 'context': '', + 'res_id': self.id, + 'display_name': ' ' + self.adname, + 'domain': '' + } + + return action + + def pydoviewallads(self): + action = self.env['ir.actions.act_window'].with_context({'default_adid': self.id})._for_xml_id( + 'DigitalSignage.act_dss_ads_view_full') + action['display_name'] = self.contract_name + # action['domain'] = '[["projectid","=","4"]]' + # context = action['context'].replace('', str(self.id)) + # context = ast.literal_eval(context) + # context.update({ + # 'create': self.active, + # 'active_test': self.active + # }) + # action['context'] = context + # return { + # 'type': 'ir.actions.act_window', + # 'view_type':'form', + # 'view_mode':'form,tree', + # 'res_model':'dss.ads', + # 'target':'current', + # 'context':'', + # 'res_id':kampagne.id, + # 'display_name' : 'Werbekampagne '+kampagne.adname, + # 'domain':'[("contract","=","context[active_id]")]' + # } + # return action + return { + 'type': 'ir.actions.act_window', + 'view_type': 'kanban', + 'view_mode': 'kanban', + 'res_model': 'dss.ads', + 'target': 'current', + 'context': '{"group_by":["parent_ad"]}', + # 'res_id':self.parent_ad, + 'display_name': 'Übersicht für ' + self.adname, + 'domain': [("contract", "=", self.contract.id)] + } + + def pydonewpread(self): + defadstate = self.env['dss.adstate'].search([('func', '=', 'STD')], limit=1).id + if not defadstate: + defadstate = 1 + if self.ad_state.func == 'STD': + parent_id = self.id + else: + parent_id = self.parent_ad.id + newkampagne = self.env['dss.ads'].create({'contract': self.contract.id, 'project': self.project.id, + 'adname': 'PRE_' + self.contract.contract_auto_name + ' ' + str( + date.today()), 'parent_ad': parent_id, 'adtype': 'PREA', + 'ad_state': defadstate}) + _logger.info('C_' + str(self.id) + ' Kampagne erzeugt : ' + str(newkampagne)) + _logger.info('Erzeugte PreWerbekampagne - Prüfe Medien : C_' + str(self.id) + 'K_' + str(newkampagne.id)) + + mediaids = [] + for feld in self.contract.werbe_feld_selected: + for media in feld.mediastructure.medias: + if not media: + _logger.info('Erzeugte PreWerbekampagne - Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( + newkampagne.id) + ' Kein Medium in MedienStructur von F_' + str(feld.id) + 'M_' + str( + media.id)) + else: + newmedia = self.env['dss.mediarelations'].create( + {'field': feld.id, 'contract': self.contract.id, 'project': self.project.id, + 'field_uuid': feld.uuid, 'ad': newkampagne.id, 'relname': media.medianame, + 'mediatype': media.id}) + _logger.info('Erzeugte PreWerbekampagne - Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( + newkampagne.id) + ' setze Vertrag für Medium : ' + str(newmedia.contract) + '/' + str( + newmedia.ad)) + mediaids.append(newmedia.id) + newkampagne.write({'need_media': [(6, 0, mediaids)]}) + _logger.info('Erzeugte PreWerbekampagne : C_' + str(self.contract.id) + 'A_' + str( + newkampagne.id) + ' setze Media ') + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': 'dss.ads', + 'target': 'current', + 'context': '', + 'res_id': newkampagne.id, + 'display_name': 'Änderung zur Werbekampagne ' + newkampagne.parent_ad.adname, + 'domain': '[("id","=","context[newkampagne.id]")]' + } + + def pydonewad(self): + for n_record in self: + resstr = n_record.uuid + _logger.info(resstr) + allads = n_record.contract.ads + _logger.info(allads) + abort = False + if allads != False: + for ad in allads: + if ad.ad_state.func != 'FIN': + if ad.adtype !='PREA': + abort = True + if abort == False: + defadstate = self.env['dss.adstate'].search([('func', '=', 'STD')], limit=1).id + if not defadstate: + defadstate = 1 + if self.ad_state.func == 'STD': + parent_id = self.id + else: + parent_id = self.parent_ad.id + newkampagne = self.env['dss.ads'].create({'contract': self.contract.id, 'project': self.project.id, + 'adname': 'AD_' + self.contract.contract_auto_name + ' ' + str( + date.today()), 'parent_ad': parent_id, 'adtype': 'KCHN', + 'ad_state': defadstate}) + _logger.info('C_' + str(self.id) + ' Kampagne erzeugt : ' + str(newkampagne)) + _logger.info('Prüfe Medien : C_' + str(self.id) + 'K_' + str(newkampagne.id)) + + mediaids = [] + for feld in self.contract.werbe_feld_selected: + for media in feld.mediastructure.medias: + if not media: + _logger.info('Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( + newkampagne.id) + ' Kein Medium in MedienStructur von F_' + str(feld.id) + 'M_' + str( + media.id)) + else: + newmedia = self.env['dss.mediarelations'].create( + {'field': feld.id, 'contract': self.contract.id, 'project': self.project.id, + 'field_uuid': feld.uuid, 'ad': newkampagne.id, 'relname': media.medianame, + 'mediatype': media.id}) + _logger.info('Prüfe Medien : C_' + str(self.contract.id) + 'K_' + str( + newkampagne.id) + ' setze Vertrag für Medium : ' + str(newmedia.contract) + '/' + str( + newmedia.ad)) + mediaids.append(newmedia.id) + newkampagne.write({'need_media': [(6, 0, mediaids)]}) + _logger.info('Click auf Werbekampagne : C_' + str(self.contract.id) + 'A_' + str( + newkampagne.id) + ' setze Media ') + + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': 'dss.ads', + 'target': 'current', + 'context': '', + 'res_id': newkampagne.id, + 'display_name': 'Änderung zur Werbekampagne ' + newkampagne.parent_ad.adname, + 'domain': '[("id","=","context[newkampagne.id]")]' + } + else: + raise ValidationError( + _("Kann neue Aktualisierung erst anlegen wenn alle vorherigen Schritte beendet wurden !")) + def pydoprecopyad(self): + for n_record in self: + resstr = n_record.uuid + _logger.info(resstr) + allads = n_record.contract.ads + _logger.info(allads) + abort = False + if allads != False: + for ad in allads: + if ad.ad_state.func != 'FIN': + if ad.adtype != 'PREA': + abort = True + if abort == False: + + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': 'dss.ads', + 'target': 'current', + 'context': '', + 'res_id': newkampagne.id, + 'display_name': 'Änderung zur Werbekampagne ' + newkampagne.parent_ad.adname, + 'domain': '[("id","=","context[newkampagne.id]")]' + } + + else: + raise ValidationError( + _("Kann neue Aktualisierung erst anlegen wenn alle vorherigen Schritte beendet wurden !")) + + def setStandardText(self, tid): + text = self.env['dss.texts'].search([('text_id', '=', tid)], limit=1) + if text: + self.write({'description': text.description}) + + def pyaddstartdate(self): + self.env['calendar.event'].search([('id','=',self.date_start_planed_calendar_event)]).unlink() + event = { + 'start': self.date_start_planed.strftime('%Y-%m-%d %H:%M:%S'), + 'stop': self.date_start_planed.strftime('%Y-%m-%d %H:%M:%S'), + 'duration': 24, + 'allday': True, + 'partner_ids': (4,self.env['dss.settings'].search([],limit=1).contact_runtime_user.partner_id.id), + 'name': 'Geplanter Start '+self.contract.contract_auto_name, + 'description': 'Geplanter Start '+self.contract.contract_auto_name+' im Projekt '+self.project.projektname, + 'user_id': self.env['dss.settings'].search([],limit=1).contact_runtime_user.id + } + _logger.debug('linking new Startevent ' + str(event) + ' ' + str(self.uuid)) + self.date_start_planed_calendar_event=self.env['calendar.event'].create(event).id + return "" + + def pyaddenddate(self): + return 1 diff --git a/models/dss_advertisefields.py b/models/dss_advertisefields.py index 959b6f2..fe6a9c9 100755 --- a/models/dss_advertisefields.py +++ b/models/dss_advertisefields.py @@ -49,7 +49,7 @@ class dssadvertisefields(models.Model): isblocked = fields.Boolean('Nach Nutzung sperren',tracking=True, default=True) # uuid = fields.Char('UUID', required=True, translate=True) - auto_feldname = fields.Char('Projekt_Feldname', required=True) + auto_feldname = fields.Char('Projekt_Feldname', default=lambda self: self._default_projektfeld(), required=True) display = fields.Char('Designname') feldname = fields.Char('Feldname', required=True) project = fields.Many2one('dss.projects' , string='Project', store=True) @@ -63,6 +63,9 @@ class dssadvertisefields(models.Model): mediastructure_medias = fields.Many2many(related='mediastructure.medias',string='Inhalt') mediarelations = fields.One2many('dss.mediarelations','relname',tracking=True) + def _default_projektfeld(self): + return "000_unbekannt" + def _default_create_date(self): return str(date.today()) diff --git a/models/dss_contract.py b/models/dss_contract.py index 9518372..ce21933 100755 --- a/models/dss_contract.py +++ b/models/dss_contract.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -* + +# Test +# Test2 + import ast import datetime import json @@ -16,6 +20,7 @@ import os.path from odoo import api, fields, models, _ from odoo import tools from . import dss_settings +from . import dss_ads from odoo.exceptions import ValidationError from datetime import date from datetime import datetime @@ -60,17 +65,26 @@ class dsscontracts(models.Model): ds = self.env['dss.ads'].search([('contract','=',self.id)],limit=1) return ds + + def _getkorrColor(self): + _logger.info('Contract get Color ') + for record in self: + record.korrectur_color = "#000000" + return "#000000" + _name = "dss.contracts" _description = "DigitalSignage Vertraege" _rec_name = "contract_auto_name" - _inherit = ['mail.thread','mail.activity.mixin','dss.triggermodel'] + _inherit = ['mail.thread','dss.activity.mixin','dss.triggermodel'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') cruuid = fields.Char(related='uuid') contract_id = fields.Char("Kundennummer",store=True,tracking=True) contract_name = fields.Char('Kurzbezeichnung', required=True,tracking=True) contract_state = fields.Many2one('dss.contractstate',group_expand='_read_group_stage_ids',tracking=True) - contract_state_color = fields.Char(related='contract_state.color',store=True) - contract_state_order = fields.Integer(related='contract_state.order',store=True) + contract_state_name = fields.Char(related='contract_state.statusname',string='Vertragsstatus - Text',store=True) + contract_state_color = fields.Char(related='contract_state.color',string='Vertragsstatus - Farbe',store=True) + contract_state_order = fields.Integer(related='contract_state.order',string='Vertragsstatus - Reihenfolge',store=True) + contract_state_minimal_kanban = fields.Boolean(related='contract_state.kanban_display_minimal',string='Kanban mininmal',store=True) contract_auto_id = fields.Char("Kundennummer",tracking=True,help="Wird berechnet aus Projektnummer + Kunden ID") contract_auto_name = fields.Char('Vertragskennug',tracking=True,help="Wird berechnet aus Kundennummer + Vertragskennung") @@ -86,13 +100,15 @@ class dsscontracts(models.Model): remark = fields.Html('Bemerkung',tracking=True) contract_writer = fields.Many2one('res.partner', tracking=True) + contract_writer_mailcc = fields.Boolean('Vertragsschr. Mail CC ?', tracking=True) vertragssumme = fields.Float('Vertragssumme :', tracking=True) provisionstyp = fields.Many2one('dss.provisionstypen', tracking=True) - provisionsteilcalc = fields.Float('Berechnete Provision :',computed='_compute_prov') - provisions = fields.Many2many('dss.provision',tracking=True) - provisionspayedpercent = fields.Float('Ausgezahlte Provision % :',computed='_compute_provisionspayedpercent') - grafiker = fields.Many2one('res.partner', placeholder="wenn vom Projekt abweichend", domain="['&',('dssinternpartner','=',True),('dssinternpartner_grafik','=',True)]", tracking=True, string="abw. Grafiker",help="Grafiker nur wenn abweichend vom Projektgrafiker") - + provisionsteilcalc = fields.Float('Berechnete Provision :') + provisions = fields.Many2many('dss.provision', tracking=True) + provisionspayedpercent = fields.Float('Ausgezahlte Provision % :',compute='_compute_provisionspayedpercent') + grafiker = fields.Many2one('res.partner', domain="['&',('dssinternpartner','=',True),('dssinternpartner_grafik','=',True)]", tracking=True, string="abw. Grafiker",help="Grafiker nur wenn abweichend vom Projektgrafiker") + real_grafiker = fields.Char('Grafiker tatsächlich', tracking=True) + contract_remark = fields.Html('Vertragshinweise',tracking=True) project = fields.Many2one('dss.projects' , string='Project', store=True,tracking=True) @@ -101,6 +117,8 @@ class dsscontracts(models.Model): project_ad_structure = fields.Many2one(related='project.grundsystem_default_adstructure', string='Aufbau') project_grundsystem_typ = fields.Char(related='project.grundsystem_typ', tracking=True) project_grafiker = fields.Many2one(related="project.project_grafiker",tracking=True) + project_system_uuid = fields.Char(related='project.grundsystemnameuuid', tracking=True) + client = fields.Many2one('res.partner',string="Kunde (wenn angelegt)",domain="['&',('dsspartner','=',True),('dsspartner_werbung','=',True)]",tracking=True,help="Nur zu Benutzen wenn Kunden als Kontakt angelegt wurde") client_id = fields.Char(string="KundenID (2Stellen)",help="Nur der 2 stellige letzte Teil der Kundennummer",tracking=True) @@ -115,10 +133,10 @@ class dsscontracts(models.Model): contact_mobil = fields.Char(related="client.mobile") contact_email = fields.Char(related="client.email") contact_web = fields.Char(related="client.website") - contact_company_name = fields.Char(related="client.name") - contact_name = fields.Char(related="client.company_name") - contact_dsspartner_vorname = fields.Char(related="client.dsspartner_name") - contact_dsspartner_name = fields.Char(related="client.dsspartner_vorname") + contact_company_name = fields.Char(related="client.company_name") + contact_name = fields.Char(related="client.name") + contact_dsspartner_vorname = fields.Char(related="client.dsspartner_vorname") + contact_dsspartner_name = fields.Char(related="client.dsspartner_name") parent_id = fields.Many2one('dss.contracts', string='Parent Task', index=True,tracking=True) @@ -136,6 +154,8 @@ class dsscontracts(models.Model): client_other_projects = fields.Many2many('dss.projects',string='Weitere Projekte',tracking=True) + client_invoices = fields.Many2many('dss.invoices',string='Rechnungsliste',tracking=True,domain='[("invoiceclientnr","=",contract_auto_id)]') + werbe_feld_selected = fields.Many2many('dss.advertisefields',string='Werbefelder',tracking=True) shortwerbe_feld_selected = fields.Char(related='werbe_feld_selected.feldname',string='Werbefelder',tracking=True) cutshortwerbe_feld_selected = fields.Char(string='gekürzte Felder',compute='_compute_cutshort') @@ -147,22 +167,24 @@ class dsscontracts(models.Model): # need_media_computed = fields.One2many('dss.mediarelations','field',compute='_get_media_list') # need_media_computed = fields.One2many('dss.mediarelations','uuid',domain="[('field','in',werbe_feld_selected)]") - main_runtime = fields.Integer('Gesamtlaufzeit',tracking=True) - split_runtime_count = fields.Integer('Laufzeit Teilungen',tracking=True) - split_runtime_time = fields.Integer('Laufzeit Sekunden',tracking=True) + main_runtime = fields.Integer('Gesamtcliplänge',tracking=True) + split_runtime_count = fields.Integer('Clip Teilungen',tracking=True) + split_runtime_time = fields.Integer('Cliplänge Sekunden',tracking=True) contract_date = fields.Date('Vertragsdatum',tracking=True) - start_date = fields.Date('Start/Auslief.datum',tracking=True) + start_date = fields.Date('Start/Auslief.datum',tracking=True,help="Datum des geplanten Startes der 1. Kampagne. Also die Uraustrahlung!") contract_cancel_mon = fields.Integer('Kündigungsfrist Monaten',tracking=True) contract_cancel_date = fields.Date('Kündigungsfrist Errechnet', tracking=True) contract_auto_extend = fields.Boolean('autom. V.Verlängerung',tracking=True) contract_auto_extend_time = fields.Char('Verl. Monate',tracking=True) + scan_vertrag = fields.Binary('Datei') + scan_vertrag_filename = fields.Char("Dateiname") # Hilft, den Dateinamen zu speichern runtimesystem = fields.Selection([('M','Monatslaufzeit'),('T','Tagelaufzeit'), ('E','Eventlaufzeit'), ('S','Sonderlaufzeit')],tracking=True) - runtime_m = fields.Integer('Laufzeit',tracking=True) - runtime_bonus_m = fields.Integer('zusätzl. Laufzeit',tracking=True) - runtime_t = fields.Integer('Laufzeit',tracking=True) - runtime_bonus_t = fields.Integer('zusätzl. Laufzeit',tracking=True) + runtime_m = fields.Integer('Laufzeit Monate',tracking=True) + runtime_bonus_m = fields.Integer('zusätzl. Laufzeit Monate',tracking=True) + runtime_t = fields.Integer('Laufzeit Tage',tracking=True) + runtime_bonus_t = fields.Integer('zusätzl. Laufzeit Tage',tracking=True) runtime_events = fields.Many2many('dss.eventdays',tracking=True) runtime_bonus_e = fields.Integer('zusätzl. Events',tracking=True) runtime_divers = fields.Char('Laufzeit',tracking=True) @@ -175,7 +197,8 @@ class dsscontracts(models.Model): base_ad = fields.Many2one('dss.ads',tracking=True) ads = fields.One2many('dss.ads','contract',tracking=True) - ads_last_ad = fields.Many2one('dss.ads', help="letzte Werbekampagne",computed='_default_get_ads_last_ad',store=True) + ads_last_ad = fields.Many2one('dss.ads', help="letzte Werbekampagne",compute='_default_get_ads_last_ad',store=True) + ads_last_adtype = fields.Selection(related='ads_last_ad.adtype') ads_last_state = fields.Many2one(related='ads_last_ad.ad_state', string="Zuständigkeit letzt Kamp",help="Zuständigkeit/Status des letzten Werbekampagnen Eintrags",store=True,readonly=False,group_expand='_expand_ads_last_state') ads_last_state_color = fields.Char(related='ads_last_ad.ad_state_color') ads_last_state_text = fields.Char(related='ads_last_ad.ad_state_text',store=True,readonly=False) @@ -184,14 +207,30 @@ class dsscontracts(models.Model): ads_last_work_state_text = fields.Char(related='ads_last_ad.work_state_text',store=True,readonly=False) ads_last_work_state_info = fields.Char(related='ads_last_ad.work_state_info',store=True,readonly=False) ads_last_todo_state = fields.Many2one(related='ads_last_ad.todo_state',string="Aufgabe letzt Kamp", help="Aufgabenstatus des letzten Werbekampagnen Eintrags",store=True,readonly=False,group_expand='_expand_ads_last_todo_state') - ads_last_todo_state_until = fields.Date(related='ads_last_ad.todo_state_until') + ads_last_todo_state_until = fields.Date(related='ads_last_ad.todo_state_until',readonly=False) ads_last_todo_state_color = fields.Char(related='ads_last_ad.todo_state_color') ads_last_todo_state_text = fields.Char(related='ads_last_ad.todo_state_text',store=True,readonly=False) + ads_last_date_zuarbeit = fields.Date(related='ads_last_ad.date_zuarbeit',readonly=False) + ads_last_date_korrekturabzug = fields.Date(related='ads_last_ad.date_korrekturabzug',readonly=False) + ads_last_date_korrekturfreigabe_ablauf = fields.Date(related='ads_last_ad.date_korrekturfreigabe_ablauf',readonly=False) + ads_last_date_korrekturfreigabe_ablauf_erfolgt = fields.Boolean(related='ads_last_ad.korrekturfreigabe_ablauf_erfolgt',readonly=False) + ads_last_date_korrekturfreigabe = fields.Date(related='ads_last_ad.date_korrekturfreigabe',readonly=False) + ads_last_date_start_planed = fields.Date(related='ads_last_ad.date_start_planed',readonly=False,help="Datum des geplanten Startes der Aktuell gültigen Kampagne !") + ads_last_date_start_real = fields.Date(related='ads_last_ad.date_start_real',readonly=False,help="Datum des wirklichen Startes der Aktuell gültigen Kampagne !") + ads_last_date_remove_planed = fields.Date(related='ads_last_ad.date_remove_planed',readonly=False) + ads_last_date_remove_real = fields.Date(related='ads_last_ad.date_remove_real',readonly=False) + ads_last_date_start_real_mail_send = fields.Boolean(related='ads_last_ad.date_start_real_mail_send',string='Kampagnen Startmail', tracking=True) + ads_last_date_start_real_mail_data = fields.Date(related='ads_last_ad.date_start_real_mail_data', tracking=True) + korrectur_color = fields.Char(string='Korrektur Text Color nach Status',compute=_getkorrColor) + ads_last_date_korrekturfreigabe_ablauf_auto_cancel = fields.Boolean(related='ads_last_ad.korrekturfreigabe_ablauf_auto_cancel', tracking=True) vnnox_zugang_erstellt = fields.Boolean('Vnnox Zugang ?',tracking=True) vnnox_zugang_username = fields.Char('Vnnox Username',tracking=True) vnnox_zugang_password = fields.Char('Vnnox Passwort',tracking=True) vnnox_zugang_gesendet = fields.Boolean('Vnnox Zugang gesendet?',tracking=True) + vnnox_playlist_checked = fields.Boolean('Vnnox Liste geprüft ?',tracking=True) + vnnox_playlist_checked_empty = fields.Boolean('Vnnox Liste war leer ?',tracking=True) + vnnox_playlist_checked_date = fields.Date('Vnnox Liste geprüft am ',tracking=True) xibo_zugang_erstellt = fields.Boolean('Xibo Zugang ?',tracking=True) xibo_zugang_username = fields.Char('Xibo Username',tracking=True) @@ -213,6 +252,13 @@ class dsscontracts(models.Model): info_partner_changes = fields.Boolean('Benachrichtigen bei Partneränderungen',tracking=True) info_partner = fields.Many2one('res.partner','Benachrichtigung an : ',tracking=True) + work_marker_1 = fields.Boolean('Markierung 1 aktiv',tracking=True) + work_marker_2 = fields.Boolean('Markierung 2 aktiv',tracking=True) + work_marker_3 = fields.Boolean('Markierung 3 aktiv',tracking=True) + work_marker_4 = fields.Boolean('Markierung 4 aktiv',tracking=True) + + marker_list = fields.Many2many('dss.marker', string='vorhandene Marker', tracking=True) + # work_state = fields.Many2one('dss.workstate',default=_default_work_state,tracking=True) # work_state_color = fields.Char(related='work_state.color') # work_state_text = fields.Char(related='work_state.statusname') @@ -226,6 +272,12 @@ class dsscontracts(models.Model): cloudlink = fields.Char('Cloud Verzeichnis',help='Verzeichnis für den Kunde innerhalb des Projekt Ordners') + tv_reach_PLZ = fields.Char(string='Reichweite PLZ',tracking=True) + ads_radius_PLZ = fields.Integer('Umkreis PLZ in Km',tracking=True) + ads_count_perYear = fields.Selection([('30000','30.000'),('60000','60.000'),('120000','120.000'),('1000000','1.000.000')],'Einblendungen',tracking=True) + ads_topics = fields.Many2many('dss.contracts_ads_topics', string='Themenliste', tracking=True) + + @api.depends('vertragssumme') def _compute_prov(self): @@ -310,7 +362,7 @@ class dsscontracts(models.Model): else: cname = record.contract_name resstr = "%s%s %s" % (record.project_id,record.client_id,cname) - cidstr: String = "%s%s" % (record.project_id,record.client_id) + cidstr = "%s%s" % (record.project_id,record.client_id) if resstr is None : resstr = 'nicht ermittelbar' _logger.info('project_id_change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name)); @@ -450,9 +502,32 @@ class dsscontracts(models.Model): @api.model def _read_group_stage_ids(self,stages,domain,order): - contract_state_ids = self.env['dss.contractstate'].search([],order='order') + _logger.info('Get Columns Contract State '+ str(stages)+' / ' + str(domain)+' / '+str(domain[0])+' / '+str(len(domain[0]))) + if (len(domain[0]) > 1): + _logger.info('get Columns Contract State ' + str(domain)+' / '+str(domain[0])) + Pid = domain[0][2] + else: + _logger.info('get Columns Contract State ' + str(domain)+' / '+str(domain[1][2])) + Pid = domain[1][2] + Myproject=self.env['dss.projects'].search([("id","=",Pid)]) + contract_state_ids = self.env['dss.contractstate'].search(["|",("systemtypdefault","=",True),("systemtypuuid","=",Myproject.grundsystemnameuuid)],order='order') +# contract_state_ids = self.env['dss.contractstate'].search([],order='order') + _logger.info('get Columns Contract State ' + str(contract_state_ids)+' / '+str(self.project_system_uuid)+' / '+str(self)+' / '+str(stages)+' / '+str(domain)+' / '+str(Myproject)) return contract_state_ids + @api.model + def _read_group_system_ids(self, stages, domain, order): + _logger.info('Get Columns System State ' + str(stages)+' / '+str(domain)+' / '+str(order)) + project_system_ids = self.env['dss.systemtypen'].search([('open_close_standard_state','=',False)], order='order') + return project_system_ids + + @api.model + def fields_view_get(self,cr,uid,view_id=None,view_type='form',context=None, toolbar=False, submenu=False): + _logger.info('Fields View Get ' + str(cr)+' / '+str(uid)+' / '+str(view)+' / '+str(parent)) + if context is None: + context={} + return res + @api.model def _default_client_id(self): return str("00") @@ -522,11 +597,17 @@ class dsscontracts(models.Model): self.runtime_calendar_event=self.env['calendar.event'].create(event).id return "" + def pyaction_dss_contract_calc_runtime(self): - if self.start_date: + if self.ads_last_date_start_real: + startdatum= self.ads_last_date_start_real + elif self.ads_last_date_start_planed: + startdatum= self.ads_last_date_start_planed + elif self.start_date: startdatum= self.start_date else: startdatum= self.contract_date + if startdatum : if self.runtimesystem == "M": bmonths = 0 @@ -561,7 +642,11 @@ class dsscontracts(models.Model): self.contract_cancel_date = enddatum - relativedelta(months=cancelmonths) def pyaction_dss_contract_calc_runtime_end(self): - if self.start_date: + if self.ads_last_date_start_real: + startdatum= self.ads_last_date_start_real + elif self.ads_last_date_start_planed: + startdatum= self.ads_last_date_start_planed + elif self.start_date: startdatum= self.start_date else: startdatum= self.contract_date @@ -801,6 +886,13 @@ class dsscontracts(models.Model): if record.contract_auto_id == "": record.contract_auto_id = cidstr + # def setRealGrafiker(self): + #for record in self: + #if self.grafiker: + #record.real_Grafiker="Test" + #return "Test" + # else: + # return self.project_grafiker def setStandardValues(self): for record in self: @@ -877,34 +969,28 @@ class dsscontracts(models.Model): for record in self: self.tokampagne() - - def trigger_action_init(self): - _logger.info('Contract Cron Running - Start '+str(self)+' start searching') - jobcontracts = self.env['dss.contracts'].search([('run_trigger', '=', True)]) - _logger.info('Contract Cron Running - Start '+str(self)+' '+str(len(jobcontracts))+' Triggergruppen gefunden') - for record in jobcontracts: - if not record: - _logger.info('Contract Cron Running No Contracts Delivered - searching') - else: - _logger.info('Contract Cron Running C_' + str(record.id) + ' Starte Triggerprüfung') - if record.run_trigger: - _logger.info('Contract Cron Running C_' + str(record.id) + ' Prüfe Triggergruppe TG_' + str(record.triggergroup.id)) - triggergroup = record.triggergroup - if not triggergroup: - _logger.info('Contract Cron Running C_' + str(record.id) + ' Triggergruppe TG_' + str(record.triggergroup.id)+' nicht gefunden !') - pass - else: - for trigger in triggergroup.triggers: - if not trigger: - pass - _logger.info('Contract Cron Running C_' + str(record.id) + ' Triggerprüfung : Keine Trigger in Gruppe !') - else: - _logger.info('Contract Cron Running C_' + str(record) + ' in Triggergruppe TG_' + str(record.triggergroup)+' Prüfe Trigger T_'+str(trigger)) - if trigger._check_trigger(): - _logger.info('Contract Cron Trigger T_' + str(trigger)+' executed ') - - - _logger.info('Contract Cron Running - Finished') + def _track_template(self, changes): + res = super()._track_template(changes) + self.trigger_track_template(changes, self) + return res + def py_open_contract_form_view(self): + return {'name': 'Budget Edit', + 'domain': [], + 'res_model': 'dss.contracts', + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'view_type': 'form', + 'res_id': self.id, +# 'target': 'new', + } + + def pyaction_vnoxx_action1(self): + return "" + + def pyaction_vnoxx_action2(self): + return "" + def pyaction_vnoxx_action3(self): + return "" \ No newline at end of file diff --git a/models/dss_importinvoicelist.py b/models/dss_importinvoicelist.py new file mode 100644 index 0000000..1bf70ba --- /dev/null +++ b/models/dss_importinvoicelist.py @@ -0,0 +1,189 @@ +import ast +import datetime +import json +import re +import uuid +import logging +import base64 +import subprocess +import tempfile +#from symbol import return_stmt + +import easywebdav +import io +import os.path +import sys +import csv +#sys.path.append('/opt/odoo') + +from odoo import api, fields, models, _ +from odoo import tools + +from odoo.exceptions import ValidationError +from . import dss_settings +from datetime import date +from datetime import datetime +from dateutil.relativedelta import relativedelta + +_logger = logging.getLogger(__name__) + + +class dssimportinvoicelist(models.Model): + _name = "dss.importinvoicelist" + _description = "DigitalSignage Rechnungsliste importieren" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "autoimportname" + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + autoimportname = fields.Char("Name des Imports",default=lambda self: self._default_name(), required=True) + import_invoicelist = fields.Binary('Datei') + import_error = fields.Text('Importfehler') + file_name = fields.Char("File Name") + alreadyimported = fields.Boolean('Bereits eingelesen?',tracking=True) + projecttype = fields.Many2one('dss.systemtypen',tracking=True) + date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date()) + user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user()) + + context = fields.Char(string='Context', compute='_get_context') + + def _get_context(self): + self.context = dict(self.env.context) + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + def _default_name(self): + calcname = 'RechnungsImport_'+str(date.today()) + return str(calcname) + + def _default_create_date(self): + return str(date.today()) + + def _default_create_user(self): + return str(self.env.user.name) + + def pyimport_invoicelist(self): + if not self.alreadyimported: + datas=base64.b64decode(self.import_invoicelist) + data=datas.decode('utf-8','ignore').splitlines() + _logger.info("Import Invoices - start data : "+str(data)+" - "+str(self.import_invoicelist)) + data.pop(0) + try: + for row in data: + BotText='' + line=row.split(";") + if (line[0] != ''): + _logger.info("Import Invoices - row : "+str(line)) + oldimport = self.env['dss.invoices'].search([('invoiceid','=',line[0])]) + if not oldimport: + client = self.env['dss.contracts'].search([('contract_auto_id','=',line[3])]) + entry = self.env['dss.invoices'].create({'invoiceid':line[0],'from_import':self.id,'invoicename':line[1],'invoiceclientnr':line[3],'contract':client.id,'invoice_date':datetime.strptime(line[4],"%d.%m.%Y"),'is_printed':(line[5]=="Endgltig"),'ammount_netto':line[6].strip(),'ammount_ust':line[7].strip(),'ammount_brutto':line[8].strip(),'is_payed':(line[11]=="Ja"),'invoice_type':line[9],'invoice_reference':line[10]}) + BotText='Rechnung ['+str(line[0])+'] für '+str(line[1])+' ('+str(line[3])+') neu erstellt als ' + if (line[11]=="Ja"): + entry.is_payed_date = self.date_create + BotText = BotText +' bezahlt' + else: + BotText = BotText +' nicht bezahlt' + client.client_invoices = [(4, entry.id)] + else: + if oldimport.is_payed: + if (line[11]=="Ja"): + _logger.info("Import Invoices - "+str(line[0])+' allready imported and payed - delete bevore import again !') + else: + _logger.info("Import Invoices - "+str(line[0])+' allready imported and payed - now not payed again !') + else: + if (line[11]=="Ja"): + oldimport.is_payed = True + oldimport.is_payed_date = self.date_create + BotText='Rechnung ['+str(line[0])+'] für '+str(line[1])+' ('+str(line[3])+') geändert in bezahlt !' + _logger.info("Import Invoices - "+str(line[0])+' allready imported and not Payed - now Payed') + else: + _logger.info("Import Invoices - "+str(line[0])+' allready imported and not Payed - not Payed again !') + if (BotText): + body = BotText + self.message_post(body=body,author_id=self.env.ref('base.partner_root').id) + + finally: + self.alreadyimported = True + else: + raise ValidationError(("Rechnungsliste wurde bereits importiert ! Bitte löschen und Import-Status zurückstetzen")) + return 1 + + def show_popup_with_message(self): + return { + 'name': 'Dynamic Popup', + 'type': 'ir.actions.act_window', + 'res_model': 'dss.importinvoicelist', + 'view_mode': 'form', + 'view_id': self.env.ref('DigitalSignage.view_dynamic_popup').id, + 'target': 'new', + 'context': { + 'dynamic_message': 'This is a custom message from the server!', + }, + } + + + + def _old_pyimport_invoicelist(self): +# Liest Rechnungsdaten aus einer CSV-Datei und erstellt Rechnungen in Odoo. +# :param env: Odoo-Umgebung +# :param csv_filepath: Pfad zur CSV-Datei + invoices = [] + try: + # CSV-Datei öffnen + data=base64.b64decode(self.import_invoicelist) + with open(csv_data, mode='r', encoding='utf-8') as file: + reader = csv.DictReader(file) + + for row in reader: + # Daten aus der Zeile lesen + partner_id = int(row['partner_id']) + invoice_date = row['Belegdatum'] + product_id = 1 + quantity = 1 + price_unit = float(row['Brutto']) + payment_state = row['bezahlt'] + + # Rechnung erstellen + invoice_data = { + 'move_type': 'out_invoice', # Typ: Verkaufsrechnung + 'partner_id': partner_id, + 'invoice_date': invoice_date, + 'payment_state': payment_state, + 'invoice_line_ids': [ + (0, 0, { + 'product_id': product_id, + 'quantity': quantity, + 'price_unit': price_unit, + }), + ], + } + + new_invoice = env['account.move'].create(invoice_data) + invoices.append(new_invoice) + + # Optional: Rechnung validieren + new_invoice.action_post() + print(f"Rechnung erstellt: ID {new_invoice.id}, Name {new_invoice.name}") + + print(f"{len(invoices)} Rechnungen wurden erfolgreich erstellt.") + + except Exception as e: + print(f"Fehler beim Verarbeiten der CSV-Datei: {e}") + return 1 + + def pyimport_takeattachment(self): + found = False + for message in self.website_message_ids: + _logger.info("Import Invoices - Get Arr. File - Message : "+str(message)) + for att in message.attachment_ids: + _logger.info("Import Invoices - Get Att. File - Attachment : "+str(att.name)) + if "CSV" in att.name: + found = True + _logger.info("Import Invoices - Get Att. File - Attachment CSV found : "+str(att.name)) + self.import_invoicelist = att.datas + break + if not found: + raise ValidationError(("Keine CSV Datei in den Anhängen gefunden !")) + + diff --git a/models/dss_invoices.py b/models/dss_invoices.py new file mode 100644 index 0000000..5584b32 --- /dev/null +++ b/models/dss_invoices.py @@ -0,0 +1,59 @@ +import uuid +import logging +#from symbol import return_stmt + +#sys.path.append('/opt/odoo') + +from odoo import api, fields, models, _ +from odoo import tools + +from odoo.exceptions import ValidationError +from . import dss_settings +from datetime import date +from datetime import datetime +from dateutil.relativedelta import relativedelta + +_logger = logging.getLogger(__name__) + + +class dssinvoices(models.Model): + _name = "dss.invoices" + _description = "DigitalSignage Rechnungen" + _inherit = ['mail.thread','mail.activity.mixin','dss.triggermodel'] + _rec_name = "invoiceid" + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date()) + user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user()) + from_import = fields.Many2one("dss.importinvoicelist",string="Importdatensatz",tracking=True) + from_import_name = fields.Char(related="from_import.autoimportname") + contract = fields.Many2one("dss.contracts",string="Importdatensatz",tracking=True) + contract_name = fields.Char(related="contract.contract_auto_name",tracking=True) + invoiceid = fields.Char("Rechnungsnummer",required=True,tracking=True) + invoicename = fields.Char("Rechnungsempfänger",tracking=True) + invoiceclientnr = fields.Char("Rechnungskundennummer",tracking=True) + invoice_date = fields.Date("Rechnungsdatum",tracking=True) + is_printed = fields.Boolean("Gedruckt",tracking=True) + ammount_netto = fields.Char("Rechnungsbetrag Nettobetrag",tracking=True) + ammount_ust = fields.Char("Rechnungs-ust",tracking=True) + ammount_brutto = fields.Char("Rechnungs Bruttobetrag",tracking=True) + is_payed = fields.Boolean("Bezahlt",tracking=True) + is_payed_date = fields.Date("Zahlung erkannt",tracking=True) + invoice_type = fields.Char("Vorgangsart",tracking=True) + invoice_reference = fields.Char("Auftragsnummer",tracking=True) + + def _track_template(self, changes): + res = super()._track_template(changes) + self.trigger_track_template(changes, self) + return res + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + + def _default_create_date(self): + return str(date.today()) + + def _default_create_user(self): + return str(self.env.user.name) + diff --git a/models/dss_mailthreat.py b/models/dss_mailthreat.py index 3011a0d..4a16560 100644 --- a/models/dss_mailthreat.py +++ b/models/dss_mailthreat.py @@ -5,6 +5,8 @@ from openerp import models, api, fields class MailThread(models.AbstractModel): _inherit = 'mail.thread' + + dss_mailRelations = fields.Char('eMailbezug') @api.model def _get_tracked_fields(self, updated_fields): diff --git a/models/dss_marker.py b/models/dss_marker.py new file mode 100644 index 0000000..cf83448 --- /dev/null +++ b/models/dss_marker.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -* + +# Test +# Test2 + +import ast +import datetime +import json +import re +import uuid +import logging +import base64 +import subprocess +import tempfile +import easywebdav +import os +import os.path + + +from odoo import api, fields, models, _ +from odoo import tools +from . import dss_settings +from odoo.exceptions import ValidationError +import sys + +_logger = logging.getLogger(__name__) + +class dssmarker(models.Model): + _name = "dss.marker" + _description = "DigitalSignage Datensatz-Marker" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "markername" + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + markerid = fields.Char('Eind. ID',help="Bitte eine Eindeutige Kennung z.B: GMARKER1112 einfallen lassen ",tracking=True) + markername = fields.Char('Name',tracking=True) + description = fields.Text('Beschreibung',tracking=True) + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) \ No newline at end of file diff --git a/models/dss_projects.py b/models/dss_projects.py index cfe25b1..43a2cb8 100755 --- a/models/dss_projects.py +++ b/models/dss_projects.py @@ -7,7 +7,10 @@ import logging import base64 import subprocess import tempfile +import requests #from symbol import return_stmt +import json +from types import SimpleNamespace import easywebdav import os @@ -34,7 +37,7 @@ class dssprojects(models.Model): _name = "dss.projects" _description = "DigitalSignage Projekte" _rec_name = "projektname" - _inherit = ['mail.thread','mail.activity.mixin'] + _inherit = ['mail.thread','mail.activity.mixin','dss.triggermodel'] projektname = fields.Char('Projektname', required=True) uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') projectid = fields.Integer('Projekt ID',tracking=True) @@ -47,13 +50,19 @@ class dssprojects(models.Model): aktstatus_color = fields.Char(related='aktstatus.color') aktstatus_icon = fields.Image(related='aktstatus.icon') description = fields.Text('Beschreibung',tracking=True) + short_partner_description = fields.Char('Kurz-Beschreibung für Kunden',tracking=True) + partner_description = fields.Text('Beschreibung für Kunden',tracking=True) systemname = fields.Many2one('dss.systems',tracking=True) grundsystemname = fields.Many2one('dss.systemtypen',group_expand='_read_group_system_ids',tracking=True) grundsystem_typ = fields.Char(related='grundsystemname.kennung',tracking=True) + grundsystemnameuuid = fields.Char(related='grundsystemname.uuid',tracking=True) grundsystemicon = fields.Image(related='grundsystemname.icon',tracking=True) grundsystem_default_adstructure = fields.Many2one(related='grundsystemname.default_adstructure',tracking=True) grundsystemicon5050 = fields.Image(related='grundsystemname.icon_5050') grundsystem_ordner = fields.Char(related='grundsystemname.default_cloud_path') + grundsystem_showonlinestate = fields.Boolean(related='grundsystemname.showonlinestate') + grundsystem_showonlinestate_type = fields.Selection(related='grundsystemname.showonlinestate_type') + standort = fields.Char('Beschreibung des Standortes') standort_strasse = fields.Char('Strasse des Projektes',tracking=True) standort_plz = fields.Char('PLZ des Projektes',tracking=True) @@ -63,6 +72,9 @@ class dssprojects(models.Model): standort_long = fields.Char('Standort Longitude',tracking=True) standort_lati = fields.Char('Standort Latitude',tracking=True) standort_visible = fields.Boolean('Auf Projekt-Karte sichtbar',tracking=True) + + zahlungsvorlauf = fields.Integer('Wochen Zahlungsvorlauf', tracking=True) + maps_name = fields.Char('Name in Google',tracking=True) maps_type = fields.Char('Type in Google',tracking=True) maps_marker = fields.Selection([('m1.png','Marker 1'),('m2.png','Marker 2'),('m3.png','Marker 3'),('m4.png','Marker 4'),('m5.png','Marker 5'),('pin.png','Marker Pin'),('pin2.png','3D Marker Pin'),('pin_display.png','Displpay Pin'),('pin_display_touch.png','TouchDisplpay Pin'),('pin_led.png','LEDWand Pin')],'Marker in Google',tracking=True) @@ -89,6 +101,7 @@ class dssprojects(models.Model): zeiten_off = fields.Datetime('veraltet',tracking=True) zeitenf_on = fields.Float('Einschaltzeit',tracking=True) zeitenf_off = fields.Float('Ausschaltzeit',tracking=True) + zeiten_notiz = fields.Char('Schaltzeiten Notizen', tracking=True) errichtet_am = fields.Date('Errichtungstag',tracking=True) standort_inout = fields.Selection([('indoor','im Gebäude'), ('outdoor','Aussenbereich'), ('semiindoor','Überdachter Aussenbereich'),('Divers','Andere Art')],tracking=True) @@ -97,6 +110,11 @@ class dssprojects(models.Model): cloudlink = fields.Char('Cloud Verzeichnis',help='Verzeichnis für das Project innerhalb des Cloud Struktur') maintains = fields.Many2many('dss.maintaintask',string="Einsätze am Projekt") + marker_list = fields.Many2many('dss.marker', string='vorhandene Marker', tracking=True) + + onlinestate = fields.Char('OnlineColor',compute='_compute_getonlinestate') + playername = fields.Char('Name des Players', tracking=True) + @api.model def _read_group_system_ids(self, stages, domain, order): project_system_ids = self.env['dss.systemtypen'].search([('open_close_standard_state','=',False)], order='order') @@ -118,11 +136,21 @@ class dssprojects(models.Model): @api.model def _compute_calendar_start(self): - self.date_start_compute=date.today() + for record in self: + if record.errichtet_am: + record.date_start_compute=record.errichtet_am + else: + record.date_start_compute=date.today() @api.model def _default_uuid(self): return str(uuid.uuid4()) + + def _track_template(self, changes): + res = super()._track_template(changes) + if self.run_trigger: + self.trigger_track_template(changes, self) + return res def pyaction_view_contracts(self): # action = self.env['ir.actions.act_window'].with_context({'default_project': self.id})._for_xml_id('DigitalSignage.action_dss_project_contracts') @@ -200,3 +228,46 @@ class dssprojects(models.Model): def pyaction_dss_project_set_def_cloud(self): self.cloudlink = str(self.env['dss.settings'].search([], limit=1).def_project_cloudpath) return True + + @api.model + def _compute_getonlinestate(self): + colorval = "#a0a0a0" + self.onlinestate = colorval + + @api.model + def compute_getonlinestate2(self,project): + proj = self.env['dss.projects'].search([('id',"=",project)]) + colorOn = str(self.env['dss.settings'].search([], limit=1).systemonline_color) + colorOff = str(self.env['dss.settings'].search([], limit=1).systemoffline_color) + _logger.info("Projekt Online Settings Check "+str(proj.grundsystem_showonlinestate_type)+' '+str(self)+' '+str(project)) + if (proj.grundsystem_showonlinestate_type == 'RPORT'): + _logger.info("Projekt RPORT Settings ") + colorval = colorOff + elif (proj.grundsystem_showonlinestate_type == 'VNNOX'): + vnurl = str(self.env['dss.settings'].search([], limit=1).vnnoxurl)+'/Rest/Logon' + vnusername = str(self.env['dss.settings'].search([], limit=1).vnnoxusername) + vnpassword = str(self.env['dss.settings'].search([], limit=1).vnnoxpassword) + _logger.info("Projekt VNNOX Settings " + str(vnurl)) + r = requests.post(vnurl, json={"password": vnpassword,"username": vnusername}) + _logger.info("Projekt VNNOX Settings Result " + str(r.status_code)) + if (str(r.status_code) == "200"): + content = str(r.json()) + index = content.find("token") + content = content[index+9:] + index = content.find("',") + token = content[:index] + _logger.info("Projekt VNNOX Settings Token : /" + str(token)+"/") + vnurl_getPlayer = str(self.env['dss.settings'].search([], limit=1).vnnoxurl)+'/Rest/Player?offset=0&limit=10&sort=name&sortType=asc&search='+str(proj.playername) + headers = {'token': token} + r = requests.get(vnurl_getPlayer, headers=headers) + if (str(r.status_code) == "200"): + content = str(r.json()) + _logger.info("Projekt VNNOX Settings Data : /" + str(content)+"/") + else: + colorval = "#a0a0a0" + colorval = colorOff + else: + colorval = "#a0a0a0" + else: + colorval = "#a0a0a0" + proj.onlinestate = colorval diff --git a/models/dss_settings.py b/models/dss_settings.py index eceeba7..0f7a276 100755 --- a/models/dss_settings.py +++ b/models/dss_settings.py @@ -36,7 +36,7 @@ class dssSettings(models.Model): def_project_cloudpath = fields.Char('Standard Projekt Pfad',tracking=True) def_project_cloudpath_sample = fields.Char('Projekt Beispiel :',store=True,tracking=True) def_contract_cloudpath = fields.Char('Standard Kunden Pfad',tracking=True) - def_contract_cloudpath_sample = fields.Char('Projekt Beispiel :',tracking=True) + def_contract_cloudpath_sample = fields.Char('Vertrags Beispiel :',tracking=True) def_contract_cloudpath_V2 = fields.Char('Standard Kunden Pfad V2',tracking=True) def_contract_cloudpath_sample_V2 = fields.Char('Projekt Beispiel V2 :',tracking=True) def_ad_cloudpath = fields.Char('Standard Kampagnen Pfad',tracking=True) @@ -52,6 +52,15 @@ class dssSettings(models.Model): show_expand_contract_group_ad_work_state = fields.Boolean('Jeden Kampagnen-Arbeitsstatus anzeigen ?',help='im Groupierungsmodus der Verträge nach Kampagnen-Arbeitsstatus alle (auch unbenutzte) Statusspalten anzeigen ?',tracking=True) show_expand_contract_group_ad_todo_state = fields.Boolean('Jeden Kampagnen-Aufgabenschritt anzeigen ?',help='im Groupierungsmodus der Verträge nach Kampagnen-Aufgabenschritt alle (auch unbenutzte) Aufgabenspalten anzeigen ?',tracking=True) freigabe_auto_time = fields.Integer('Auto Freigabetage',help='Automatische Freigabe nach x Tagen',tracking=True) + tv_vertragsankuendigung_actionID = fields.Integer('TV Vertragsankündigung ActionID',help="Aktion die ausgeführt wird, wenn im Web-Vertragseingang der Button Vertragsankündigung geklickt wird.",tracking=True) + systemonline_color = fields.Char('Farbe Online',tracking=True) + systemoffline_color = fields.Char('Farbe Offline',tracking=True) + vnnoxurl = fields.Char('VNNox URL',tracking=True) + vnnoxusername = fields.Char('VNNox Username',tracking=True) + vnnoxpassword = fields.Char('VNNox Password',tracking=True) + rporturl = fields.Char('RPort URL',tracking=True) + rportusername = fields.Char('RPort Username',tracking=True) + rportpassword = fields.Char('RPort Password',tracking=True) def _get_settingvalue(self,valuename): @@ -115,12 +124,37 @@ class dssSettings(models.Model): return str(uuid.uuid4()) @api.model - def saveConfig(self,savemodel,activefields): - _logger.info("Config speichern "+str(savemodel)+" / "+str(activefields)) + def saveConfig(self,tableInfo): + _logger.info("Config speichern "+str(tableInfo)) + activefields = tableInfo[3] for field in activefields: - feldwerte = activefields.get(field) - for wert in feldwerte: - _logger.info("Config speichern : "+str(field)+" / "+str(wert)+" -> "+str(feldwerte.get(wert))) + _logger.info("Config speichern : "+str(field)+" / "+str(tableInfo[0])+" -> "+str(tableInfo[1])+" "+str(tableInfo[2])) + myview = self.env['dss.viewsettings'].search(['&',("user","=",self.env.user.name),("model_view","=",tableInfo[1]),("model_datensatz","=",tableInfo[0]),("viewtype","=",tableInfo[2]),("column","=",field[0])]) + if not myview: + _logger.info("Config speichern : noch keine gespeicherten Daten") + else: + myview.unlink() + self.env['dss.viewsettings'].create({ + 'model_view':tableInfo[1], + 'model_datensatz':tableInfo[0], + 'viewtype':tableInfo[2], + 'user':self.env.user.name, + 'user_id':self.env.user.id, + 'column':field[0], + 'column_size':field[1], + 'state_visible':field[2], + 'state_collapse':field[3] + }) + return 0 + + @api.model + def resetConfig(self,tableInfo): + _logger.info("Config reset "+str(tableInfo)) + myview = self.env['dss.viewsettings'].search(['&',("user","=",self.env.user.name),("model_view","=",tableInfo[1]),("model_datensatz","=",tableInfo[0]),("viewtype","=",tableInfo[2])]) + if not myview: + _logger.info("Config Reset : noch keine gespeicherten Daten") + else: + myview.unlink() return 0 @@ -131,10 +165,13 @@ class dssSettingsSave(models.Model): _description = "DigitalSignage Ansicht Einstellungen" _inherit = [] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') - model = fields.Many2one('ir.model',string='Ansichtsmodel') - viewtype = fields.Char('Ansichtstyp') user = fields.Char('User') + user_id = fields.Many2one('res.users',string='User_id') + model_view = fields.Char('Model') + model_datensatz = fields.Char('Datensatz') + viewtype = fields.Char('Ansichtstyp') column = fields.Char('Spalte') + column_size = fields.Char('Spalten Grösse') state_visible = fields.Char('Status sichtbar') state_collapse = fields.Char('Status zusammengeklappt') @@ -146,4 +183,7 @@ class dssSettingsSave(models.Model): def _default_create_user(self): return str(self.env.user.name) + def _default_create_user_id(self): + return self.env.user.id + diff --git a/models/dss_systemtypen.py b/models/dss_systemtypen.py index ec4d8bd..9fffa7f 100755 --- a/models/dss_systemtypen.py +++ b/models/dss_systemtypen.py @@ -40,7 +40,7 @@ class dsssystemtypen(models.Model): farbe = fields.Char('Grundfarbe') icon = fields.Image() icon_5050 = fields.Image("Icon 50",compute='_compute_icon_5050') - default_adstructure = fields.Many2one('dss.adstructures',String='Standard-Werbeaufbau', tracking=True) + default_adstructure = fields.Many2one('dss.adstructures',string='Standard-Werbeaufbau', tracking=True) default_cloud_path = fields.Char('Standard Cloud Path', tracking=True) email_template_welcome = fields.Many2one('mail.template',string='Mailvorlage für Willkommen', tracking=True) email_template_zuarbeit = fields.Many2one('mail.template',string='Mailvorlage für Zuarbeiterrinnerung', tracking=True) @@ -49,6 +49,8 @@ class dsssystemtypen(models.Model): open_close_standard_state = fields.Boolean('Wenn Leer geschlossen ? ', tracking=True) open_close_user_state = fields.Boolean('Leer-Verhalten user',compute='_get_user_openstate',tracking=True) order = fields.Integer('Reihenfolge') + showonlinestate = fields.Boolean('OnlineStatus zeigen') + showonlinestate_type = fields.Selection([('RPORT','RPort Status'),('VNNOX','Vnnox System')]) @@ -88,4 +90,4 @@ class dssstatesave(models.Model): stategroup = fields.Selection([('SYSTYP','Systemtypen'),('CONTYP','Vertragsstatus')],'Status Gruppe', required=True) state = fields.Char('Status', required=True) user = fields.Char('Benutzer', required=True) - state_open = fields.Boolean('Verhalten ', tracking=True) + state_open = fields.Boolean('Verhalten ') diff --git a/models/dss_trigger.py b/models/dss_trigger.py index e37d13c..349ff49 100644 --- a/models/dss_trigger.py +++ b/models/dss_trigger.py @@ -1,13 +1,111 @@ import uuid import logging +import datetime from odoo import api, fields, models, _ from odoo import tools +from datetime import datetime +from datetime import date from odoo.exceptions import ValidationError +from dateutil.relativedelta import relativedelta import sys _logger = logging.getLogger(__name__) +class dsstriggerconditions(models.Model): + _name = "dss.triggerconditions" + _description = "DigitalSignage Trigger Bedingungen" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "triggerconditionname" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date()) + date_lastedit = fields.Date('Änderungsdatum') + user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user()) + user_lastedit = fields.Char('Änderungsuser') + + triggerconditionname = fields.Char('Trigger Bedingungsname',tracking=True) + trigger_table = fields.Many2one('ir.model','Nutzbar in',help='Für welche Daten ist dieser Bedingung gültig ?',tracking=True) + trigger_condition_type = fields.Selection([('WERT','Feld gleich einem Wert'),('MARKER','Marker vorhanden')],'Prüfungsart',tracking=True) + trigger_field = fields.Many2one('ir.model.fields',string="Bedingungsfeld", help='Prüfungsfeldname in der Tabelle - für dieses Feld wird der Wert geprüft',tracking=True) + trigger_operator = fields.Selection([('NGLEICH','Feld gleich dem Wert'),('GGLEICH','Feld größer/gleich dem Wert'),('KGLEICH','Feld kleiner/gleich dem Wert'),('UGLEICH','Feld ungleich dem Wert'),('ENTHAELT','Feld enthällt dem Wert')],'Feldwertoperator',tracking=True) + trigger_value_opperator = fields.Selection([('TAG','Aktueller Tag'),('TIME','Aktuelle Zeit'),('JAHR','Aktuelles Jahr'),('BTRUE','Boolean Wahr'),('BFALSE','Boolean Falsch'),('FIX','Wert')],'Vergleichswert',tracking=True) + trigger_negate = fields.Boolean('Ergebnis Negieren',tracking=True) + trigger_marker_check = fields.Many2one('dss.marker','Marker',help='Welcher Marker soll eingefügt werden ?',tracking=True) + trigger_value = fields.Char('Fix Wert',tracking=True) + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + def _default_create_date(self): + return str(date.today()) + + def _default_create_user(self): + return str(self.env.user.name) + + + def trigger_CheckCond(self,Dataset,Condition): + if (Condition.trigger_condition_type == "MARKER"): + Wert = "" + else: + fieldname = Condition.trigger_field.name + field = Dataset._fields[fieldname] + field_type = field.type + Compare = False + if (field_type == "date"): + Wert = str(Dataset[fieldname]) + elif (field_type == "many2one"): + Wert = str(Dataset[fieldname].id) + else: + Wert = Dataset[fieldname] + if (Condition.trigger_condition_type == "WERT"): + _logger.info("Trigger in CheckConditions - checking conditions : "+str(Dataset)+" field : "+str(fieldname)+' ('+str(Condition.trigger_value_opperator)+') -> '+str(Condition)) + OPP = Condition.trigger_operator + if (Condition.trigger_value_opperator== "TAG"): + TargetValue= str(date.today()) + if (Wert == False): + Wert = "1900-01-01" + elif (Condition.trigger_value_opperator== "TIME"): + TargetValue= str(datetime.now()) + if (Wert == False): + Wert = "00:00" + elif (Condition.trigger_value_opperator== "JAHR"): + TargetValue= str(date.today()) + if (Wert == False): + Wert = "1900-01-01" + elif (Condition.trigger_value_opperator== "BTRUE"): + TargetValue= str(True) + elif (Condition.trigger_value_opperator== "BFALSE"): + TargetValue= str(False) + elif (Condition.trigger_value_opperator== "FIX"): + TargetValue= str(Condition.trigger_value) + _logger.info("Trigger in CheckConditions - Vergleich : ("+str(Wert)+') ('+str(field_type)+' -> '+str(OPP)+' -> '+str(TargetValue)) + Compare = False + + if OPP=="NGLEICH": + Compare = str(Wert) == str(TargetValue) + _logger.info("Trigger in CheckConditions - Vergleich GLEICH : "+str(Wert)+' = '+str(TargetValue)+" = "+str(Compare)) + if OPP=="UGLEICH": + Compare = str(Wert) != str(TargetValue) + _logger.info("Trigger in CheckConditions - Vergleich NGLEICH : "+str(Wert)+' <> '+str(TargetValue)+" = "+str(Compare)) + if OPP=="GGLEICH": + Compare = str(Wert) >= str(TargetValue) + _logger.info("Trigger in CheckConditions - Vergleich GGLEICH : "+str(Wert)+' >= '+str(TargetValue)+" = "+str(Compare)) + if OPP=="KGLEICH": + Compare = str(Wert) <= str(TargetValue) + _logger.info("Trigger in CheckConditions - Vergleich KGLEICH : "+str(Wert)+' <= '+str(TargetValue)+" = "+str(Compare)) + elif (Condition.trigger_condition_type == "MARKER"): + _logger.info("Trigger in CheckConditions - checking conditions : "+str(Dataset.marker_list)+" Marker : "+str(Condition.trigger_marker_check)) + Compare = Condition.trigger_marker_check.id in Dataset.marker_list.mapped('id') + if Condition.trigger_negate: + Compare = not Compare + _logger.info("Trigger in CheckConditions - NOT Invert : = "+str(Compare)) + + dotrigger = Compare + return dotrigger + + class dsstriggergroups(models.Model): _name = "dss.triggergroups" _description = "DigitalSignage Trigger Gruppen" @@ -21,8 +119,10 @@ class dsstriggergroups(models.Model): user_lastedit = fields.Char('Änderungsuser') triggergroupname = fields.Char('Trigger Gruppenname',tracking=True) - trigger_table = fields.Many2one('ir.model','Nutzbar in',help='Für welche Daten ist dieser Tigger gültig ?',track_visibility='onchange',tracking=True) + trigger_table = fields.Many2one('ir.model','Nutzbar in',help='Für welche Daten ist dieser Tigger gültig ?',tracking=True) triggers = fields.Many2many('dss.triggertypes',string='Enthaltene Trigger',tracking=True) + trigger_allgemein = fields.Boolean('Trigger allgemein gültig ?',tracking=True) + trigger_cron = fields.Boolean('Triggergruppe für Zeitsteuerung ?',tracking=True) @api.model def _default_uuid(self): @@ -33,6 +133,205 @@ class dsstriggergroups(models.Model): def _default_create_user(self): return str(self.env.user.name) + + @api.model + def run_triggers(self, changes, Dataset, triggers): + _logger.info("Trigger in run_triggers ! - start count :"+str(len(triggers)) ) + for trig in triggers: + _logger.info("Trigger in run_triggers - Working on : "+str(trig.id)) + dochecktrigger = False + + if (changes == False): + dochecktrigger = True + elif (trig.triggertyp == "COND"): + dochecktrigger = True + else: + if (trig.trigger_field.name in changes): + dochecktrigger = True + + if (dochecktrigger): + isinintitable = self.env['dss.triggermodel.execute'].search(['&',('trigger','=',trig.id),('data_uuid','=',Dataset.uuid)]) + dotrigger = False + if (not isinintitable) and trig.trigger_init_trigger: + _logger.info("Trigger in run_triggers - first run and allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig)) + dotrigger = True + elif (not isinintitable) and ((not trig.trigger_init_trigger) and (not trig.trigger_onlyinit_trigger)): + _logger.info("Trigger in run_triggers - first run but not allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig)) + dotrigger = False + elif (isinintitable) and trig.trigger_onlyinit_trigger: + _logger.info("Trigger in run_triggers - not first run but only first: "+str(isinintitable)+' -> '+str(trig.trigger_onlyinit_trigger)+' -> '+str(trig)) + dotrigger = False + else: + _logger.info("Trigger in run_triggers - not first run but only first: "+str(isinintitable)+' -> '+str(trig)) + dotrigger = True + + if dotrigger: + fieldname = trig.trigger_value_field.name + _logger.info("Trigger in run_triggers - checking conditions : "+str(trig.triggertyp)+" field : "+str(fieldname)+' -> '+str(trig.trigger_value_field)) + if (trig.triggertyp == "FIELD_B"): + Wert = Dataset[fieldname] + _logger.info("Trigger in run_triggers - Boolean check : "+str(Dataset[fieldname])+" vs "+str(Wert)+' -> '+str(trig.trigger_value_Bool)) + if trig.trigger_value_Bool: + if Wert: + _logger.info("Trigger in run_triggers - value true - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool)) + dotrigger = True + else: + _logger.info("Trigger in run_triggers - value true - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool)) + dotrigger = False + else: + if Wert: + _logger.info("Trigger in run_triggers - value False - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool)) + dotrigger = False + else: + _logger.info("Trigger in run_triggers - value False - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool)) + dotrigger = True + elif (trig.triggertyp == "FIELD_S"): + #Wert= self.env[trig.trigger_table.model].get(fieldname) + WertDB = self.env[trig.trigger_table.model].search([('id', '=', Dataset.id)]) + field = WertDB._fields[fieldname] + field_type = field.type + Wert = "" + if field_type=="many2one": + Wert = str(Dataset[fieldname].id) +# Dataset[fieldname].model +# SubWertDB = self.env[].search([('id', '=', field.id)]) +# Wert = SubWertDB.id + if field_type=="char": + Wert = str(Dataset[fieldname]) + _logger.info("Trigger in run_triggers - specific value : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value)+' - '+str(field)+' / '+str(field_type)) + if (str(Wert) == str(trig.trigger_value)): + _logger.info("Trigger in run_triggers - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value)) + dotrigger = True + else: + _logger.info("Trigger in run_triggers - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value)) + dotrigger = False + elif (trig.triggertyp == "FIELD_K"): + dotrigger = False + elif (trig.triggertyp == "MANUAL"): + dotrigger = False + elif (trig.triggertyp == "COND"): + dotrigger = True + + if trig.trigger_plus_conditions and dotrigger: + runtrigger = True + for SingleC in trig.trigger_conditions: + _logger.info("Trigger in run_triggers - Multible Conditions found "+str(trig.trigger_conditions)+' -> '+str(SingleC)+' -> '+str(runtrigger)) + runtrigger = SingleC.trigger_CheckCond(Dataset,SingleC) and runtrigger + else: + runtrigger = dotrigger + + if runtrigger: + execds = '' + self.trigger_run(trig,Dataset,isinintitable,execds) + + def trigger_run(self,trig,Dataset,isinintitable,execds): + for akt in trig.trigger_aktionen: + if akt: + _logger.info("Trigger in Trigger_run - Aktion "+str(akt)) + akt.Doexecute(Dataset) + execds = execds + ";" +str(Dataset.id)+'/'+str(akt.id) + if not isinintitable: +# self.env['dss.triggermodel.execute'].create({'trigger':trig.id,'data_uuid':Dataset.uuid,'execdatetime':date.today(),"trigger_action":akt.id}) + self.env['dss.triggermodel.execute'].create({'trigger':trig.id,'data_uuid':Dataset.uuid,'execdatetime':date.today(),"trigger_table":self.env['ir.model'].search([('model','=',str(akt.trigger_table.model))]).id,"trigger_action":akt.id}) +# akt._run_action_code_multi(akt._get_eval_context(akt)) + else: + _logger.info("Trigger in Trigger_run - no Aktion in Trigger !") + for aktgroup in trig.trigger_aktionen_groups: + if aktgroup: + for akt in aktgroup: + _logger.info("Trigger in Trigger_run - Aktion "+str(akt)) + akt.Doexecute(Dataset,trig,isinintitable) + execds = execds + ";" +str(Dataset.id)+'/'+str(akt.id) + + return execds + + + def run_cron_triggers(self,triggergroup,triggers): + _logger.info("Trigger in run_Cron_Triggers ! - Start für : "+str(self.trigger_table.model)) + resultstr = "Anz. Trigger : "+str(len(triggers)) + resultsimplestr = "Anz. Trigger : "+str(len(triggers)) + triggercnt = 0 + cntExecDS_init = 0 + cntExecDS = 0 + cntExecCont = 0 + cntExecContTrue = 0 + cntExecAS = 0 + dscnt = 0 + execds = "" + for trig in triggers: + triggercnt += 1 + resultstr = resultstr+" Trigger "+str(triggercnt)+' : ' + if (trig.triggertyp == "FILTER"): + lea=trig.trigger_raw_condition.split(',') + _logger.info("Trigger in run_Cron_triggers - : Filtered Datasets "+str(lea)) + AllDataset = self.env[str(triggergroup.trigger_table.model)].search([lea]) + else: + AllDataset = self.env[str(triggergroup.trigger_table.model)].search([]) + _logger.info("Trigger in run_Cron_triggers - : All Datasets "+str(len(AllDataset))) + resultstr = " Count Data : "+str(len(AllDataset)) + for Dataset in AllDataset: + dscnt += 1 + resultstr = resultstr+" Data "+str(dscnt)+' : ' + _logger.info("Trigger in run_Cron_triggers - : "+str(Dataset)+" check allready execute : "+str(Dataset.uuid)+" "+str(date.today())) + isinintitable = self.env['dss.triggermodel.execute'].search(['&',('trigger','=',trig.id),('data_uuid','=',Dataset.uuid),('execdatetime','=',date.today())]) + dotrigger = False + if (not isinintitable) and trig.trigger_init_trigger: + _logger.info("Trigger in run_Cron_triggers - first run and allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig)) + dotrigger = True + elif (not isinintitable) and ((not trig.trigger_init_trigger) and (not trig.trigger_onlyinit_trigger)): + _logger.info("Trigger in run_Cron_triggers - first run but not allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig)) + dotrigger = False + elif (isinintitable) and trig.trigger_onlyinit_trigger: + _logger.info("Trigger in run_Cron_triggers - not first run but only first (or day): "+str(isinintitable)+' -> '+str(trig.trigger_onlyinit_trigger)+' -> '+str(trig)) + dotrigger = False + else: + _logger.info("Trigger in run_Cron_triggers - running no given restrictions : "+str(isinintitable)+' -> '+str(trig)) + dotrigger = True + + if dotrigger: + cntExecDS_init += 1 + if (trig.triggertyp == "FILTER"): + runtrigger = True + elif (trig.triggertyp == "COND"): + runtrigger = True + for SingleC in trig.trigger_conditions: + cntExecCont += 1 + _logger.info("Trigger in run_Cron_triggers - Multible Conditions found "+str(trig.trigger_conditions)+' -> '+str(SingleC)+' -> '+str(runtrigger)) + conres = SingleC.trigger_CheckCond(Dataset,SingleC) + runtrigger = conres and runtrigger + if conres: + cntExecContTrue += 1 + else: + _logger.info("Trigger Abgebrochen ! in ZeitGruppen sind nur BedingungsTrigger Erlaubt "+str(trig.trigger_aktionen)) + runtrigger = False + + _logger.info("Trigger in run_Cron_triggers - Conditions result "+str(runtrigger)) + if runtrigger: + cntExecDS += 1 + _logger.info("Trigger wird Ausgeführt - Aktionen "+str(trig.trigger_aktionen)) + resultstr = resultstr + " Anz Aktionen : "+str(len(trig.trigger_aktionen)) + execds = self.trigger_run(trig,Dataset,isinintitable,execds) + + _logger.info("Result :"+resultstr) + _logger.info("-------------------------------------- CRON Trigger Result --------------------------------------------------------------------") + _logger.info("Result :"+resultsimplestr) + _logger.info("Result : Anz. CondChecks : "+str(cntExecDS_init)) + _logger.info("Result : Anz. Conditions : "+str(cntExecCont)) + _logger.info("Result : Anz. ConditionsTrue : "+str(cntExecContTrue)) + _logger.info("Result : Anz. ConditionsFalse : "+str(cntExecCont - cntExecContTrue)) + _logger.info("Result : Anz. Conditionok : "+str(cntExecDS)) + _logger.info("Result : Anz. ExecAction : "+str(cntExecAS)) + _logger.info("Result : Exec Datasets : "+execds) + _logger.info("-------------------------------------------------------------------------------------------------------------------------------") + + + def exectrigger(self): + _logger.info("Trigger Sofort Execute !"+str(self)) + if self.trigger_cron: + self.run_cron_triggers(self,self.triggers) + else: + self.run_triggers(False,False,self.triggers) + class dsstriggertypes(models.Model): @@ -47,15 +346,23 @@ class dsstriggertypes(models.Model): user_lastedit = fields.Char('Änderungsuser') triggername = fields.Char('Triggername',tracking=True) + triggergruppe = fields.Char('Triggergruppe',tracking=True) trigger_active = fields.Boolean('Trigger Aktiv ?',tracking=True) - triggertyp = fields.Selection([('FIELD_A','Feldänderung allgemein'),('FIELD_S','Feldänderung spezifisch'),('FIELD_K','Feldwert berechnet'),('MANUAL','Menuell ausgelösst')],'Triggertyp',tracking=True) + triggertyp = fields.Selection([('FIELD_A','Feldänderung allgemein'),('FIELD_S','Feldänderung spezifisch'),('FIELD_B','Feldänderung BOOL'),('FIELD_K','Feldwert berechnet'),('COND','Bedingungen prüfen'),('MANUAL','Manuell ausgelösst'),('FILTER','Manuell gefiltert')],'Triggertyp',tracking=True) trigger_table = fields.Many2one('ir.model','Nutzbar in',help='Für welche Daten ist dieser Tigger gültig ?',tracking=True) - trigger_field = fields.Many2one('ir.model.fields', help='Feldname in der Tabelle',tracking=True) + trigger_field = fields.Many2one('ir.model.fields', string="Auslöser Feld",help='Triggerfeldname in der Tabelle - Änderungen an dem Feld lösen den Trigger aus',tracking=True) trigger_operator = fields.Selection([('NGLEICH','Feld gleich dem Wert'),('GGLEICH','Feld größer/gleich dem Wert'),('KGLEICH','Feld kleiner/gleich dem Wert'),('UGLEICH','Feld ungleich dem Wert'),('ENTHAELT','Feld enthällt dem Wert')],'Feldwertoperator',tracking=True) + trigger_time_opperator = fields.Selection([('TAG','Aktueller Tag'),('TIME','Aktuelle Zeit'),('JAHR','Aktuelles Jahr'),('FIX','Feste Zeit')],'Vergleichswert',tracking=True) trigger_init_trigger = fields.Boolean('Ausl. bei 1. Änderung ?',help='Soll der Trigger bereits beim setzen des 1. Wertes auslösen?',tracking=True) + trigger_onlyinit_trigger = fields.Boolean('Ausl. nur bei 1. Änderung ?',help='Soll der Trigger nur beim setzen des 1. Wertes auslösen?',tracking=True) + trigger_plus_conditions = fields.Boolean('Zusätz. Bedingungen prüfen',help='Soll der Trigger zusätzlich zur Auslösung Bedingungen prüfen?',tracking=True) + trigger_value_field = fields.Many2one('ir.model.fields',string="Vergleichsfeld Feld", help='Prüfungsfeldname in der Tabelle - für dieses Feld wird der Wert geprüft',tracking=True) trigger_value = fields.Char('Feldwert für Trigger',tracking=True) - trigger_old_value = fields.Char('Letzter-Feldwert für Trigger',tracking=True) - trigger_aktionen = fields.Many2many('ir.actions.server',string='Aktionen bei auslösen des Triggers',tracking=True) + trigger_value_Bool = fields.Boolean('Feldwert für Trigger (Ja/Nein)',tracking=True) + trigger_conditions = fields.Many2many('dss.triggerconditions',string='Bedingungen zum auslösen des Triggers',tracking=True) + trigger_aktionen = fields.Many2many('dss.triggeractions',string='Aktionen bei auslösen des Triggers',tracking=True) + trigger_aktionen_groups = fields.Many2many('dss.triggeractions.groups',string='Aktionsgruppen bei auslösen des Triggers',tracking=True) + trigger_raw_condition = fields.Char('Datensatz Auswahl',tracking=True) @api.model def _default_uuid(self): @@ -73,25 +380,7 @@ class dsstriggertypes(models.Model): value = getattr(value,part) return value - def _check_trigger(self): - for record in self: - _logger.info('Trigger Check TR_' + str(record)+' Begin') - if record.trigger_active: - _logger.info('Trigger Check TR_' + str(record) + ' Check Field F_'+str(record.trigger_field.name)+' of model M_'+str(record.trigger_table.model)+' Feld-Typ :'+str(record.trigger_field.ttype)) - if record.trigger_field.ttype in ['char','text','html']: - val = self.env[record.trigger_table.model]._origin.read([record.trigger_field.name]) - elif record.trigger_field.ttype in ['selection']: - val = self.env[record.trigger_table.model]._origin.read([record.trigger_field.name])[0] - elif record.trigger_field.ttype in ['one2many']: - val = self.env[record.trigger_table.model]._origin.read([record.trigger_field.name]).ids - elif record.trigger_field.ttype in ['many2one']: -# val = self.getfield(self.env[record.trigger_table.model],record.trigger_field.name+'.uuid') - val = self.env[record.trigger_table.model]._fields[record.trigger_field.name].string - else: - val = False - record.trigger_old_value = str(val) - _logger.info('Trigger Check TR_' + str(record)+' oldValue '+str(record.trigger_old_value)+' newValue '+str(val)) - _logger.info('Trigger Check TR_' + str(record)+' Ende') + def _check_trigger(self,DataRecord): return "" class dsstriggeractions(models.Model): @@ -99,25 +388,60 @@ class dsstriggeractions(models.Model): _description = "DigitalSignage Trigger Aktionen" _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "triggeractionname" + _order = "triggeractionprio" uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date()) date_lastedit = fields.Date('Änderungsdatum') user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user()) user_lastedit = fields.Char('Änderungsuser') + BotText = fields.Html('Ausgabetext') + triggeractionprio = fields.Integer('Priorität',tracking=True) + Info_Subject = fields.Char('InfoÜberschrift') + followaction = fields.Boolean('Folgeaktion vorhanden',tracking=True) - triggeractionname = fields.Char('Triggeraktionname',track_visibility='onchange',tracking=True) - triggeractiontyp = fields.Selection([('EMAIL','EMail senden'),('ACTIV','Aufgabe erzeugen'),('DSEDIT','Datensatz ändern'),('TUYA','Tuya Aktion auslössen')],'Aktionstyp',tracking=True) + has_trigger_action_conditions = fields.Boolean('Bedingungen vorhanden',help="Sind Bedingungen vor Ausführung vorhanden?",tracking=True) + trigger_conditions = fields.Many2many('dss.triggerconditions',string='Bedingungen zum Ausführen der Aktion',tracking=True) + + trigger_aktionen_active = fields.Boolean('Trigger Aktion aktiv',tracking=True) + trigger_table = fields.Many2one('ir.model','Nutzbar in',help='Für welche Daten ist dieser Tigger gültig ?',tracking=True) + triggeractionname = fields.Char('Triggeraktionname',tracking=True) + triggeractiontyp = fields.Selection([('EMAIL','EMail an senden'),('NOTIZ','Notitz erstellen'),('MESSA','Message an Follower senden'),('CHANNEL','Message an Channel senden'),('ACTIV','Aufgabe erzeugen'),('MARKER','Marker eintragen'),('DSEDIT','Akt. Datensatz ändern'),('TUYA','Tuya Aktion auslössen'),('PRUEF','Wert prüfen')],'Aktionstyp',tracking=True) email_getfrom = fields.Selection([('FIX','Email fest hinterlegt'),('DATA','Email in Feld hinterlegt')],'Emailadresse von',tracking=True) email_fix_email_sender = fields.Many2one('res.partner','Absender',help='Email Sender Adresse der Aktion',tracking=True) - email_fix_email = fields.Many2one('res.partner','Empfänger',help='Email Emüfänger Adresse für Benachrichtigung/Triggeraktion',tracking=True) - email_data_table = fields.Many2one('ir.model','Nutzbar in',help='Für welche Daten ist diese Aktion gültig ?',tracking=True) - email_data_field = fields.Many2one('ir.model.fields', help='Feldname in der Tabelle',tracking=True) + email_fix_email = fields.Many2one('res.partner','Empfänger fix',help='Email Emüfänger Adresse für Benachrichtigung/Triggeraktion',tracking=True) + email_data_table = fields.Many2one('ir.model','EmailDaten in',help='Für welche Daten ist diese Aktion gültig ?',tracking=True) + email_data_field = fields.Many2one('ir.model.fields','Empfänger Feld', help='Feldname in der Tabelle',tracking=True) email_template = fields.Many2one('mail.template','Emailvorlage',tracking=True) + activity_user = fields.Many2one('res.users','Empfänger der Aufgabe',tracking=True) + activity_type = fields.Many2one('mail.activity.type','Art der Aufgabe',tracking=True) + activity_date_type = fields.Selection([('TOPLU','Von heute in x Tagen'),('TOFIX','An einem festen Datum'),('TOFIXDB','An einem festen Datum der Datenbank'),('TOPLUDB','An einem festen Datum der Datenbank + x Tage')],tracking=True) + activity_date_type_add_days = fields.Integer('x Tage Aufschlag',tracking=True) + activity_date_type_fix = fields.Date('Planungsdatum ',tracking=True) + activity_text = fields.Text('Inhalt der Aufgabe',tracking=True) + field = fields.Char('Feldname',help='Feldname in o.g. Tebelle.',tracking=True) type_s = fields.Char('Feldwertoperator',tracking=True) value_s = fields.Char('Feldwert für Trigger',tracking=True) + action_table = fields.Many2one('ir.model','Nutzbar in',help='Für welche Daten ist dieser Tigger gültig ?',tracking=True) + action_field = fields.Many2one('ir.model.fields', string="Auslöser Feld",help='Triggerfeldname in der Tabelle - Änderungen an dem Feld lösen den Trigger aus',tracking=True) + action_test_id = fields.Char('TestID für Triggeraktion',tracking=True) + action_value_type = fields.Selection([('FIXT','Fester Wert'),('BOOL','Boolischen Wert'),('DATE','Aktuelles Datum'),('DATX','Aktuelles Datum + X'),('CALC','Berechneter Wert'),('GROS','Aus anderer Quelle')],'Wertart des Eintrags',tracking=True) + action_value_fix = fields.Char('Wert zum setzen',tracking=True) + action_value_bool = fields.Boolean('Boolwert zum setzen',tracking=True) + action_value_fix_plus = fields.Integer('Zuschlag für Berechnung',tracking=True) + + action_value_from_same_table_bool = fields.Boolean('Wert aus akt. Datensatz ?',tracking=True) + action_value_from_table = fields.Many2one('ir.model','Daten aus ',help='Aus welcher Datenmenge soll der Wert geholt werden ?',tracking=True) + action_value_from_field = fields.Many2one('ir.model.fields','Feld aus ',help='Aus welchem Feld soll der Wert geholt werden ?',tracking=True,domain='[("model_id","=",action_value_from_table)]') + + postChannel = fields.Char('Kanalnummer für Post :',tracking=True) + + follow_action_id = fields.Many2one('dss.triggeractions', string="Nachfolgende Aktion",help='Aktion welche direkt im Anschluss unabhänig des Ablaufs ausgeführt wird',tracking=True) + + insert_marker = fields.Many2one('dss.marker','Marker',help='Welcher Marker soll eingefügt werden ?',tracking=True) + @api.model def _default_uuid(self): return str(uuid.uuid4()) @@ -129,14 +453,222 @@ class dsstriggeractions(models.Model): return str(self.env.user.name) + def Doexecute(self,Dataset): + runaction = False + if self.has_trigger_action_conditions: + runaction = True + for SingleC in self.trigger_conditions: + _logger.info("Trigger in run_triggers - Multible Conditions found "+str(self.trigger_conditions)+' -> '+str(SingleC)+' -> '+str(runaction)) + runaction = SingleC.trigger_CheckCond(Dataset,SingleC) and runaction + else : + runaction=True + if runaction: + if (self.triggeractiontyp == 'EMAIL'): +# mail_pool = self.env['mail.mail'] +# values={} +# values.update({'subject': 'Your subject'}) +# values.update({'email_to': 'To email'}) +# values.update({'body_html': 'body' }) +# values.update({'body': 'body' }) +# values.update({'res_id': 'obj.id' }) #[optional] here is the record id, where you want to post that email after sending +# values.update({'model': ''Object Name }) #[optional] here is the object(like 'project.project') to whose record id you want to post that email after sending +# msg_id = mail_pool.create(values) +# # And then call send function of the mail.mail, +# if msg_id: +# mail_pool.send([msg_id]) + ccmailto = self.email_template.email_cc + ccmailto_org = self.email_template.email_cc + if not ccmailto: + ccmailto='' + mailto = "" + if self.email_getfrom == "FIX": + mailto = "" + for partner in self.email_fix_email: + mailto = mailto+';'+partner.email + _logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - FIX Empfänger : '+str(self.email_getfrom)+' -> '+str(mailto)) + elif self.email_getfrom == "DATA": + mailto = str(Dataset[self.email_data_field.name]) + _logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - DATA Empfänger : '+str(self.email_getfrom)+' -> '+str(mailto)) + else: + mailto = "technik@logumedia.de" + _logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - NONE Empfänger : '+str(self.email_getfrom)+' -> '+str(mailto)) + if 'contract_writer_mailcc' in self.env[str(self.trigger_table.model)]._fields: + mailcc = Dataset["contract_writer_mailcc"] + if mailcc: + VsPartner = self.env['res.partner'].search([('id','=',Dataset.contract_writer.id)]) + ccmailto = ccmailto+';'+VsPartner.email + _logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email CC Writer - FIX Empfänger : '+str(VsPartner)+' -> '+str(ccmailto)+' + '+str(VsPartner.email)) + _logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Template : '+str(self.email_template)+" Empfänger :"+str(mailto)+'/'+str(ccmailto)+' -> '+str(Dataset)) + self.email_template.email_to = mailto + self.email_template.email_cc = ccmailto + self.email_template.send_mail(Dataset.id,force_send=True) + self.email_template.email_cc = ccmailto_org + elif (self.triggeractiontyp == 'DSEDIT'): + _logger.info('Trigger Aktion TRA_' + str(self)+' Setze Wert für DS_'+str(Dataset)+' FLD_'+str(self.action_field.name)+' - Typ : '+str(self.action_value_type)+' -> '+str(self.action_value_bool)) + EditFeld = Dataset[self.action_field.name] + field = Dataset._fields[self.action_field.name] + field_type = field.type + if (self.action_value_type == 'BOOL'): + _logger.info('Trigger Aktion TRA_' + str(self)+' Setze Wert - Typ : '+str(self.action_value_type)+' / '+str(EditFeld)+' -> '+str(self.action_value_bool)) + EditFeld = Dataset.write({self.action_field.name : self.action_value_bool}) + if (self.action_value_type == 'DATE'): + _logger.info('Trigger Aktion TRA_' + str(self)+' Setze Wert - Typ : '+str(self.action_value_type)+' / '+str(EditFeld)+' -> '+str(date.today())) + EditFeld = Dataset.write({self.action_field.name : date.today()}) + if (self.action_value_type == 'DATX'): + _logger.info('Trigger Aktion TRA_' + str(self)+' Setze Wert - Typ : '+str(self.action_value_type)+' / '+str(EditFeld)+' -> '+str(date.today())+' + '+str(self.action_value_fix_plus)+' = '+str(date.today()+ relativedelta(days=self.action_value_fix_plus))) + EditFeld = Dataset.write({self.action_field.name : date.today() + relativedelta(days=self.action_value_fix_plus)}) + if (self.action_value_type == 'FIXT'): + _logger.info('Trigger Aktion TRA_' + str(self)+' Setze Wert - Typ : '+str(self.action_value_type)+' / '+str(EditFeld)+' (Type : '+str(field_type)+') -> '+str(self.action_value_fix)) + if (field_type == "many2one"): + Dataset[self.action_field.name] = int(self.action_value_fix) + elif (field_type == "date"): + Dataset.write({self.action_field.name : self.action_value_fix}) + else: + Dataset.write({self.action_field.name : self.action_value_fix}) + if (self.action_value_type == 'GROS'): + if (self.action_value_from_same_table_bool): + Dataset[self.action_field.name] = Dataset[self.action_value_from_field.name] + + elif (self.triggeractiontyp == 'ACTIV'): + deadline = datetime.now() + if self.activity_date_type == 'TOPLU': + deadline = datetime.now() + deadline = deadline + relativedelta(days=self.activity_date_type_add_days) + elif self.activity_date_type == 'TOFIX': + deadline = self.activity_date_type_fix + elif self.activity_date_type == 'TOFIXDB': + deadline = Dataset[self.action_field.name] + elif self.activity_date_type == 'TOPLUDB': + deadline = Dataset[self.action_field.name] + deadline = deadline + relativedelta(days=self.activity_date_type_add_days) + + if not Dataset: + _logger.info('Trigger Aktion TRA_' + str(self)+' Create Task - No Dataset - use Test '+str(self.trigger_table)+' '+str(self.action_test_id)) + ds = self.env[self.trigger_table.model].search([('id','=',self.action_test_id)]) + else: + ds = Dataset + if not self.trigger_table: + _logger.info('Trigger Aktion TRA_' + str(self)+' Create Task - No Model '+str(ds)+' '+str(self.trigger_table)) + else: + _logger.info('Trigger Aktion TRA_' + str(self)+' Create Task '+str(self.Info_Subject)+' ('+str(self.activity_user)+') - Model : '+str(self.trigger_table.id)+'/'+str(ds.id)+' '+str(deadline)) + self.env['mail.activity'].create({ + 'display_name': self.Info_Subject, + 'summary': self.activity_text, + 'date_deadline': deadline, + 'user_id': self.activity_user.id, + 'res_id': ds.id, + 'res_model_id': self.trigger_table.id, + 'activity_type_id': self.activity_type.id + }) + _logger.info('Trigger Aktion TRA_' + str(self)+' Create Task '+str(self.Info_Subject)+' ('+str(self.activity_user)+') - Model : '+str(self.trigger_table.id)+'/'+str(Dataset.id)+' '+str(deadline)) + elif (self.triggeractiontyp == 'MARKER'): + _logger.info('Trigger Aktion TRA_' + str(self)+' Insert Marker '+str(Dataset.marker_list)+' ('+str(self.insert_marker)+') - Model : '+str(self.trigger_table.id)+'/'+str(Dataset.id)) + Dataset.marker_list = [(4,self.insert_marker.id)] + elif (self.triggeractiontyp == 'CHANNEL'): + if (not self.BotText): self.BotText='' + body = self.BotText + '('+str(self.id)+')' + Channel = self.env["mail.channel"].browse(int(self.postChannel)) + Channel.message_post(body=body,author_id=self.env.ref('base.partner_root').id,subject=self.Info_Subject,message_type="comment",subtype_xmlid="mail.mt_comment") + _logger.info('Trigger Aktion TRA_' + str(self)+' Post channel '+str(self.postChannel)+' ('+str(Channel.name)+') - Text : '+str(body)) + elif (self.triggeractiontyp == 'NOTIZ'): + if (not self.BotText): self.BotText='' + body = self.BotText + '('+str(self.id)+')' + # body = 'Für die Werbekampagne '+str(record.adname)+' im Vertrag '+str(record.contract.contract_auto_name)+' des Projektes '+str(record.project.projektname)+' wurde der Korekturabzug automatisch durch Zeitablauf bestätigt !' + Dataset.message_post(body=body,author_id=self.env.ref('base.partner_root').id,subject=self.Info_Subject) + # self.env['mail.message'].create({'message_type': 'comment','subtype_id': self.env.ref('mail.mt_comment').id, + # 'model': 'mail.channel','res_id': self.env.ref('mail.channel_all_employees').id,'body': body,'subject': akt.Info_Subject,}) + _logger.info('Trigger Aktion TRA_' + str(self)+' Create notice '+str(self.Info_Subject)+' + Text : '+str(body)) + elif (self.triggeractiontyp == 'MESSA'): + partner_ids = Dataset.message_follower_ids.partner_id.ids + if (not self.BotText): self.BotText='' + body = self.BotText + '('+str(self.id)+')' + #while '{#' in str(body): + _logger.info('Trigger Aktion TRA_' + str(self)+' Sende Message '+str(partner_ids)+' + Text : '+str(body)) + # Dataset.message_post(body=body,author_id=self.env.ref('base.partner_root').id,subject=self.Info_Subject,partner_ids=partner_ids) + # self.env['mail.message'].create({'message_type': 'comment','subtype_id': self.env.ref('mail.mt_comment').id, + # 'model': 'mail.channel','res_id': self.env.ref('mail.channel_all_employees').id,'body': body,'subject': akt.Info_Subject,}) + + return True + + def exectriggeraction(self): + _logger.info('Trigger Aktion Sofortauslösung TRA_' + str(self)+' '+str(self.trigger_table.model)+' Testid :'+str(self.action_test_id)) + Dataset = self.env[str(self.trigger_table.model)].search([('id','=',self.action_test_id)], limit=1) + self.Doexecute(Dataset) + + class dsstriggermodel(models.Model): _name = "dss.triggermodel" _description = "DigitalSignage Trigger Model für Inherit" _rec_name = "trigger_uuid" trigger_uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') - run_trigger = fields.Boolean('Trigger aktiv',tracking=True) - triggergroup = fields.Many2one('dss.triggergroups',string='Triggergruppe',tracking=True,default=True) + run_trigger = fields.Boolean('Trigger aktiv') + run_uni_trigger = fields.Boolean('Allgemeine Trigger aktiv',default=True) + run_uni_sub_trigger = fields.Boolean('Allgemeine Trigger (Sub) aktiv',default=True) + triggergroup = fields.Many2one('dss.triggergroups',string='Triggergruppe') @api.model def _default_uuid(self): return str(uuid.uuid4()) + + + @api.model + def trigger_track_template(self, changes, Dataset): + _logger.info("Trigger in track_template - "+str(Dataset)+" - Changes : "+str(changes)) + if Dataset.run_trigger: + _logger.info("Trigger in track_template - "+str(Dataset.triggergroup)+" - Changes : "+str(changes)) + Dataset.triggergroup.run_triggers(changes, Dataset, Dataset.triggergroup.triggers) + + if Dataset.run_uni_trigger: + _logger.info("Trigger in track_template - UNIVERSAL - Suche Triggergruppen : id :"+str(Dataset._name)) + triggergroups = self.env['dss.triggergroups'].search([('trigger_table','=',Dataset._name),('trigger_allgemein','=',True)]) + _logger.info("Trigger in track_template - UNIVERSAL - Triggergruppen gefunden : "+str(triggergroups)) + for trig in triggergroups: + trig.run_triggers(changes, Dataset, trig.triggers) + + +class dsstriggeractiongroupss(models.Model): + _name = "dss.triggeractions.groups" + _description = "DigitalSignage Trigger Aktionen Gruppen" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "triggeractiongroupname" + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date()) + date_lastedit = fields.Date('Änderungsdatum') + user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user()) + user_lastedit = fields.Char('Änderungsuser') + triggeractiongroupname = fields.Char('Triggeraktion Gruppenname',tracking=True) + trigger_list = fields.Many2many('dss.triggeractions',string='Enthaltene Trigger',help='Welche Trigger sollen ausgeführt werden ?',tracking=True) + action_test_id = fields.Char('TestID für Triggeraktion',tracking=True) + trigger_table = fields.Many2one('ir.model','Nutzbar in',help='Für welche Daten ist dieser Tigger gültig ?',tracking=True) + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + def _default_create_date(self): + return str(date.today()) + + def _default_create_user(self): + return str(self.env.user.name) + + def Doexecute(self,Dataset,trig,isinintitable): + for akt in self.trigger_list: + _logger.info("Trigger in ExecTrigger_Group - Aktion "+str(akt)) + akt.Doexecute(Dataset) + if not isinintitable: + self.env['dss.triggermodel.execute'].create({'trigger':trig.id,'data_uuid':Dataset.uuid,'execdatetime':date.today(),"trigger_table":self.env['ir.model'].search([('model','=',str(akt.trigger_table.model))]).id,"trigger_action":akt.id}) + else: + _logger.info("Trigger in Trigger_group_run - no Aktion in Trigger !") + + + def DoexecuteGroup(self,Dataset): + for akt in self.trigger_list: + _logger.info("Trigger in ExecTrigger_Group - Aktion "+str(akt)) + akt.Doexecute(Dataset) + + + def exectriggeraction_group(self): + _logger.info('Trigger Aktion Sofortauslösung TRA_G' + str(self)+' '+str(self.trigger_table.model)+' Testid :'+str(self.action_test_id)) + Dataset = self.env[str(self.trigger_table.model)].search([('id','=',self.action_test_id)], limit=1) + self.DoexecuteGroup(Dataset) + diff --git a/models/dss_triggerexecute.py b/models/dss_triggerexecute.py new file mode 100644 index 0000000..bb24d9a --- /dev/null +++ b/models/dss_triggerexecute.py @@ -0,0 +1,34 @@ +import uuid +import logging +import datetime + +from odoo import api, fields, models, _ +from odoo import tools +from datetime import datetime +from datetime import date +from odoo.exceptions import ValidationError +import sys + +_logger = logging.getLogger(__name__) + +class dsstriggerexecuted(models.Model): + _name = "dss.triggermodel.execute" + _description = "DigitalSignage Trigger Execution list" + _rec_name = "uuid" + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + trigger = fields.Many2one('dss.triggertypes') + data_uuid = fields.Char('Datensatz') + trigger_table = fields.Many2one('ir.model','Model') + trigger_action = fields.Many2one('dss.triggeractions','Aktion') + execdatetime = fields.Datetime('Ausfuerhungszeit',default=lambda self: self._default_create_date()) + trigger_user = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user()) + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + def _default_create_date(self): + return datetime.now() + + def _default_create_user(self): + return str(self.env.user.name) \ No newline at end of file diff --git a/models/dss_web_contracts.py b/models/dss_web_contracts.py new file mode 100644 index 0000000..1477b9a --- /dev/null +++ b/models/dss_web_contracts.py @@ -0,0 +1,308 @@ +# -*- coding: utf-8 -* + +# Test +# Test2 + +import ast +import datetime +import json +import re +import uuid +import logging +import base64 +import subprocess +import tempfile +import easywebdav +import os +import os.path + + +from odoo import api, fields, models, _ +from odoo import tools +from . import dss_settings +from . import dss_ads +from odoo.exceptions import ValidationError +from datetime import date +from datetime import datetime +from babel.dates import format_date +from dateutil.relativedelta import relativedelta +from pyffmpeg import FFmpeg +from tuya_iot import TuyaOpenAPI, TUYA_LOGGER +from tuya_connector import TuyaOpenAPI, TUYA_LOGGER +import sys + +TUYA_LOGGER.setLevel(logging.DEBUG) +_logger = logging.getLogger(__name__) + +class dsscontracts(models.Model): + + _name = "dss.web_contracts" + _description = "DigitalSignage Web_Vertraege" + _rec_name = "contract_auto_name" + _inherit = ['mail.thread','mail.activity.mixin','dss.triggermodel'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + cruuid = fields.Char(related='uuid') + contract_id = fields.Char("Kundennummer",store=True,tracking=True) + contract_auto_id = fields.Char("Kundennummer automatisch",tracking=True,help="Wird berechnet aus Projektnummer + Kunden ID") + contract_name = fields.Char('Kurzbezeichnung', required=True,tracking=True) + contract_auto_name = fields.Char('Vertragskennung',tracking=True,help="Wird berechnet aus Kundennummer + Vertragskennung") + + contract_writer = fields.Many2one('res.partner', domain="['&',('dsspartner','=',True),('dsspartner_vertrieb','=',True)]", tracking=True) + contract_writer_formular = fields.Char('Vertragsschreiber Formular', tracking=True) + contract_type = fields.Selection([('TV','TV'),('Web','Web')], 'Vertragstyp', tracking=True) + + remark = fields.Char('Bemerkungen',tracking=True) + + vertragssumme = fields.Float('Vertragssumme :', tracking=True) + + contract_remark = fields.Html('Vertragshinweise',tracking=True) + + project = fields.Many2one('dss.projects' , string='Project', store=True,tracking=True) + project_id = fields.Integer(related='project.projectid', string='Project ID') + projectIid = fields.Integer('Project IID',tracking=True) + + client_id = fields.Char(string="KundenID (2Stellen)",help="Nur der 2 stellige letzte Teil der Kundennummer",tracking=True) + client_short_company = fields.Char('Firmenname Kunde',tracking=True) + client_short_vorname = fields.Char('Vorname Kunde',tracking=True) + client_short_name = fields.Char('Name Kunde',tracking=True) + client_short_strasse = fields.Char('Strasse Kunde',tracking=True) + client_short_plz = fields.Char('PLZ Kunde',tracking=True) + client_short_ort = fields.Char('Ort Kunde',tracking=True) + client_short_land = fields.Many2one('res.country','Land Kunde',tracking=True) + client_short_email = fields.Char('Email Kunde',tracking=True) + client_short_telefon = fields.Char('Telefon Kunde',tracking=True) + client_short_mobil = fields.Char('Mobilfunk Kunde',tracking=True) + client_short_website = fields.Char('Webseite Kunde',tracking=True) + client = fields.Many2one('res.partner',string="Kunde (wenn angelegt)",domain="['&',('dsspartner','=',True),('dsspartner_werbung','=',True)]",tracking=True,help="Nur zu Benutzen wenn Kunden als Kontakt angelegt wurde") + + + client_other_projects = fields.Many2many('dss.projects',string='Weitere Projekte',tracking=True) + + werbe_feld = fields.Char(string='Werbefelde(r)',tracking=True) + werbe_feld_selected = fields.Many2many('dss.advertisefields',string='Werbefelder',tracking=True) + werbe_feld_tv = fields.Selection([('L-Banner','L-Banner'),('Countdown','Countdown')], 'Paket', tracking=True) + werbe_feld_web = fields.Selection([('Standard','Standard'),('Premium','Premium')], 'Paket', tracking=True) + zahlweise = fields.Selection([('einmalig','einmalig'),('jaehrlich','jährlich'),('sonder','Sonderzahlweise')], 'Zahlweise', tracking=True) + + main_runtime = fields.Integer('Gesamtcliplänge',tracking=True) + split_runtime_count = fields.Integer('Clip Teilungen',tracking=True) + split_runtime_time = fields.Integer('Cliplänge Sekunden',tracking=True) + + contract_date = fields.Date('Vertragsdatum',tracking=True) + contract_cancel_date = fields.Date('Kündigungsfrist Datum', tracking=True) + + contract_cancel_mon = fields.Integer('Kündigungsfrist Monaten',tracking=True) + + contract_auto_extend = fields.Boolean('autom. V.Verlängerung',tracking=True) + contract_auto_extend_time = fields.Char('Verl. Monate',tracking=True) + + runtimesystem = fields.Selection([('J','Jahreslaufzeit'),('M','Monatslaufzeit'),('T','Tagelaufzeit'), ('E','Eventlaufzeit'), ('S','Sonderlaufzeit')],'Laufzeit',tracking=True) + runtime_j = fields.Integer('Laufzeit Jahre',tracking=True) + runtime_m = fields.Integer('Laufzeit Monate',tracking=True) + runtime_bonus_m = fields.Integer('zusätzl. Laufzeit Monate',tracking=True) + runtime_t = fields.Integer('Laufzeit Tage',tracking=True) + runtime_bonus_t = fields.Integer('zusätzl. Laufzeit Tage',tracking=True) + runtime_events = fields.Many2many('dss.eventdays',tracking=True) + runtime_bonus_e = fields.Integer('zusätzl. Events',tracking=True) + runtime_divers = fields.Char('Laufzeit Spezial',tracking=True) + runtime_finish = fields.Date('LaufzeitEnde',tracking=True) + runtime_calendar_event = fields.Integer('Kalendereintrag ID',tracking=True) + + date_start_planed = fields.Date(string='geplantes Startdatum', tracking=True) + date_remove_planed = fields.Date(string='geplantes Enddatum', tracking=True) + + tv_reach_PLZ = fields.Char('Reichweite PLZ',tracking=True) + ads_radius_PLZ = fields.Integer('Umkreis PLZ in Km',tracking=True) + ads_count_perYear = fields.Selection([('30000','30.000'),('60000','60.000'),('120000','120.000'),('1000000','1.000.000')],'Einblendungen',tracking=True) +# ads_count_perYear_related = fields.Selection(related='dss.contracts.ads_count_perYear',tracking=True) + ads_topic = fields.Selection([('auto','Auto'),('beauty','Beauty & Fashion'),('wirtschaft','Wirtschaft, Finanzen & News'),('food','Food'),('gesundheit','Gesundheit'),('lifestyle','Lifestyle'),('living','Living'),('entertainment','Entertainment'),('reise','Reise'),('technik','Technik'),('individuell','Individuell')],'Themen', tracking=True) + ads_topics = fields.Many2many('dss.contracts_ads_topics', string='Themenliste', tracking=True) + grafik_zuarbeitBis = fields.Date("Zuarbeit bis", tracking=True) + grafikerstellung = fields.Boolean("Grafikerstellung Logumedia", tracking=True) + + scan_vertrag = fields.Binary('Datei') + file_name = fields.Char(string='Dateiname') + + erfasst_in_odoo = fields.Boolean('In Odoo erfasst') + erfasst_in_agenda = fields.Boolean('In Agenda erfasst') + rechnungsanfrage_RTL = fields.Boolean('Bei RTL angekündigt') + +# def action_send_email(self): +# """ Sendet eine E-Mail mit den Inhalten des Objekts """ +# template = self.env.ref('dss.email_template_my_model') +# if template: +# template.send_mail(self.id, force_send=True) + + def pydonewpartner1(self): + _logger.info("create new partner...") + + def pydonewpartner(self): + _logger.info("create new partner...") + fullname = str(self.client_short_vorname) + ' ' +str(self.client_short_name) + newcontact = self.env['res.partner'].create({'name': fullname, + 'email': self.client_short_email, + 'phone': self.client_short_telefon, + 'mobile': self.client_short_mobil, + 'street': self.client_short_strasse, + 'city': self.client_short_ort, + 'zip': self.client_short_plz, + 'country_id': self.env['res.country'].search([('code', '=', 'DE')], limit=1).id, + 'company_type': 'person', # 'company' oder 'person', + 'website': self.client_short_website, + 'commercial_company_name': self.client_short_company, + 'dsspartner': True, + 'dsspartner_werbung': True + }) + self.client = newcontact.id + + + def pydonewcontract(self): + _logger.info("create new contract...") + newcontract = self.env['dss.contracts'].create({'project_id': self.project_id, + 'project': self.project.id, + 'client_id': self.client_id, + 'contract_auto_name': self.contract_auto_name, + 'contract_auto_id': self.contract_auto_id, + 'contract_name': self.contract_name, + 'contract_state': self.env['dss.contractstate'].search([("statusname","=","Angelegt")]).id, + 'werbe_feld_selected': self.werbe_feld_selected, + 'client': self.client.id, + 'client_short_vorname': self.client_short_vorname, + 'client_short_email': self.client_short_email, + 'client_short_telefon': self.client_short_telefon, + 'client_short_mobil': self.client_short_mobil, + 'client_short_strasse': self.client_short_strasse, + 'client_short_ort': self.client_short_ort, + 'client_short_plz': self.client_short_plz, + 'client_short_website': self.client_short_website, + 'client_short_company': self.client_short_company, + 'ads_count_perYear': self.ads_count_perYear, + 'runtimesystem': self.runtimesystem, + 'runtime_m': self.runtime_m, + 'runtime_t': self.runtime_t, + 'contract_auto_extend': self.contract_auto_extend, + 'contract_cancel_date': self.contract_cancel_date, + 'runtime_events': self.runtime_events, + 'tv_reach_PLZ': self.tv_reach_PLZ, + 'ads_radius_PLZ': self.ads_radius_PLZ, + 'ads_topics': self.ads_topics, + 'contract_auto_extend': self.contract_auto_extend, + 'contract_date': self.contract_date, + 'scan_vertrag': self.scan_vertrag + }) + _logger.info("create new Werbekampagne...") + newWK = self.env['dss.ads'].create({'contract': newcontract.id, + 'project': newcontract.project.id, + 'adname': 'WK '+self.contract_auto_name, + 'adtype': 'MAIN', + 'date_start_planed': self.date_start_planed, + 'date_remove_planed': self.date_remove_planed, + #'work_state_info': 'ZA bis: '+str(self.grafik_zuarbeitBis)+' / '+self.remark + 'work_state_info': 'ZA bis: '+format_date(self.grafik_zuarbeitBis,format='dd.MM.yy',locale='de_DE')+' / '+self.remark + }) + self.erfasst_in_odoo = True + + def pysendemail_rtl(self): + """Sendet eine E-Mail über das Template""" + myAction = self.env['dss.triggeractions.groups'].search([('id','=',self.env['dss.settings'].search([], limit=1).tv_vertragsankuendigung_actionID)], limit=1) #Id der TriggerAktion + myAction.action_test_id = self.id #Id des Datensatzes für den die Mail ist + myAction.exectriggeraction_group() + """ + template = self.env['mail.template'].search([('id','=',44)], limit=1) + if template: + template.send_mail(self.id, force_send=True) + self.rechnungsanfrage_RTL = True + email_body = template._render_field('body_html', [self.id])[self.id] # HTML-Body rendern + email_subject = template._render_field('subject', [self.id])[self.id] # Betreff rendern + email_to = template._render_field('email_to', [self.id])[self.id] # Empfänger rendern + self.message_post(body=f"Betreff: {email_subject}
Empfänger: {email_to}

{email_body}",subject="E-Mail gesendet",message_type='comment',subtype_xmlid="mail.mt_comment") + """ + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + + #Vertragskennungen bei onChange anpassen + @api.onchange('client_id') + def _onchange_client_id(self): + for record in self : + if record.contract_name == '' : + cname = 'unbekannter Kunden' + else: + cname = record.contract_name + resstr = "%s%s %s" % (record.project_id,record.client_id,cname) + cidstr = "%s%s" % (record.project_id,record.client_id) + if resstr is None : + resstr = 'nicht ermittelbar' + _logger.info('Contract_client_id_change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name)) + self.contract_auto_name = resstr + self.contract_auto_id = cidstr + + @api.onchange('project_id') + def _onchange_project_id(self): + for record in self : + if record.contract_name == '' : + cname = 'unbekannter Kunden' + else: + cname = record.contract_name + resstr = "%s%s %s" % (record.project_id,record.client_id,cname) + cidstr = "%s%s" % (record.project_id,record.client_id) + if resstr is None : + resstr = 'nicht ermittelbar' + _logger.info('project_id_change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name)) + self.contract_auto_name = resstr + self.contract_auto_id = cidstr + +# @api.onchange('project') +# def _onchange_project(self): +# self.project_id = self.project.project_id + + @api.onchange('contract_name') + def _onchange_contract_name(self): + for record in self : + if record.contract_name == '' : + cname = 'unbekannter Kunden' + else: + cname = record.contract_name + resstr = "%s%s %s" % (record.project_id,record.client_id,cname) + cidstr = "%s%s" % (record.project_id, record.client_id) + if resstr is None : + resstr = 'nicht ermittelbar' + _logger.info('Contract_Name_Change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name)) + if not self.contract_auto_name: + self.contract_auto_name = resstr + if not self.contract_auto_id: + self.contract_auto_id = cidstr + if self.contract_auto_id == "": + self.contract_auto_id = cidstr + + @api.onchange('contract_auto_id') + def _onchange_contract_auto_id(self): + for record in self : + if record.contract_name == '' : + cname = 'unbekannter Kunden' + else: + cname = record.contract_name + resstr = "%s%s %s" % (record.project_id,record.client_id,cname) + cidstr = "%s%s" % (record.project_id, record.client_id) + if resstr is None: + resstr = 'nicht ermittelbar' + _logger.info('Contract_auto_id_change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name)) + if not self.contract_auto_name: + self.contract_auto_name = resstr + if not self.contract_auto_id: + self.contract_auto_id = cidstr + if self.contract_auto_id == "": + self.contract_auto_id = cidstr + + + +class dsscontractsadstopics(models.Model): + _name = 'dss.contracts_ads_topics' + _description = "DigitalSignage Werbung ATV Themen" + _rec_name = "anzeigename" + _inherit = ['mail.thread','mail.activity.mixin','dss.triggermodel'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + + thema = fields.Char(string="Name") + anzeigename = fields.Char(string='Anzeigename') \ No newline at end of file diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv index cf68593..4db6d9c 100755 --- a/security/ir.model.access.csv +++ b/security/ir.model.access.csv @@ -21,11 +21,24 @@ digitalsignage_dss_mediarelations_group_user,access.dss.mediarelations,model_dss digitalsignage_dss_advertisefields_group_user,access.dss.advertisefields,model_dss_advertisefields,base.group_user,1,1,1,1 digitalsignage_dss_import_group_user,access.dss.import,model_dss_import,base.group_user,1,1,1,1 digitalsignage_dss_settings_group_user,access.dss.settings,model_dss_settings,base.group_user,1,1,1,1 +digitalsignage_dss_viewsettings_group_user,access.dss.viewsettings,model_dss_viewsettings,base.group_user,1,1,1,1 digitalsignage_dss_screendesign_group_user,access.dss.screendesign,model_dss_screendesign,base.group_user,1,1,1,1 digitalsignage_dss_triggertypes_group_user,access.dss.triggertypes,model_dss_triggertypes,base.group_user,1,1,1,1 digitalsignage_dss_triggeractions_group_user,access.dss.triggeractions,model_dss_triggeractions,base.group_user,1,1,1,1 +digitalsignage_dss_triggerexecute_group_user,access.dss.triggermodel.execute,model_dss_triggermodel_execute,base.group_user,1,1,1,1 digitalsignage_dss_triggergroups_group_user,access.dss.triggergroups,model_dss_triggergroups,base.group_user,1,1,1,1 digitalsignage_dss_maintaintask_group_user,access.dss.maintaintask,model_dss_maintaintask,base.group_user,1,1,1,1 digitalsignage_dss_provision_group_user,access.dss.provision,model_dss_provision,base.group_user,1,1,1,1 digitalsignage_dss_provisionstypen_group_user,access.dss.provisionstypen,model_dss_provisionstypen,DigitalSignage.group_prov_user,1,1,1,1 digitalsignage_dss_payintervals_group_user,access.dss.payintervals,model_dss_payintervals,base.group_user,1,1,1,1 +digitalsignage_dss_importinvoicelist_group_user,access.dss.importinvoicelist,model_dss_importinvoicelist,base.group_user,1,1,1,1 +digitalsignage_dss_web_contracts_group_user,access.dss_web_contracts,model_dss_web_contracts,base.group_user,1,1,1,1 +digitalsignage_dss_contracts_ads_topics_group_user,access.dss_contracts_ads_topics,model_dss_contracts_ads_topics,base.group_user,1,1,1,1 +digitalsignage_dss_triggerconditions_group_user,access.dss.triggerconditions,model_dss_triggerconditions,base.group_user,1,1,1,1 +digitalsignage_dss_marker_group_user,access.dss.marker,model_dss_marker,base.group_user,1,1,1,1 +digitalsignage_dss_triggeractions_groups_user,access.dss.triggeractions.groups,model_dss_triggeractions_groups,base.group_user,1,1,1,1 +DigitalSignage_dss_triggervalues,access.dss.triggervalues,DigitalSignage.model_dss_triggervalues,base.group_user,1,0,0,0 +DigitalSignage_dss_statesave,access.dss.statesave,DigitalSignage.model_dss_statesave,base.group_user,1,0,0,0 +DigitalSignage_dss_activity_mixin,access.dss.activity_mixin,DigitalSignage.model_dss_activity_mixin,base.group_user,1,0,0,0 +DigitalSignage_dss_triggermodel,access.dss.triggermodel,DigitalSignage.model_dss_triggermodel,base.group_user,1,0,0,0 +DigitalSignage_dss_invoices,access.dss.invoices,DigitalSignage.model_dss_invoices,base.group_user,1,1,1,1 diff --git a/static/src/img/img_107_b_2.jpg b/static/src/img/img_107_b_2.jpg new file mode 100644 index 0000000..cf20d9e Binary files /dev/null and b/static/src/img/img_107_b_2.jpg differ diff --git a/static/src/img/img_108_b_2.jpg b/static/src/img/img_108_b_2.jpg new file mode 100644 index 0000000..6f65cdc Binary files /dev/null and b/static/src/img/img_108_b_2.jpg differ diff --git a/static/src/img/img_108_b_3.jpg b/static/src/img/img_108_b_3.jpg new file mode 100644 index 0000000..17afef3 Binary files /dev/null and b/static/src/img/img_108_b_3.jpg differ diff --git a/static/src/img/img_113_b_2.jpg b/static/src/img/img_113_b_2.jpg new file mode 100644 index 0000000..7ab1a10 Binary files /dev/null and b/static/src/img/img_113_b_2.jpg differ diff --git a/static/src/img/img_113_b_3.jpg b/static/src/img/img_113_b_3.jpg new file mode 100644 index 0000000..00c5773 Binary files /dev/null and b/static/src/img/img_113_b_3.jpg differ diff --git a/static/src/img/img_119_b_2.jpg b/static/src/img/img_119_b_2.jpg new file mode 100644 index 0000000..34791a5 Binary files /dev/null and b/static/src/img/img_119_b_2.jpg differ diff --git a/static/src/img/img_119_b_3.jpg b/static/src/img/img_119_b_3.jpg new file mode 100644 index 0000000..6e83b8b Binary files /dev/null and b/static/src/img/img_119_b_3.jpg differ diff --git a/static/src/img/img_121_b.jpg b/static/src/img/img_121_b.jpg new file mode 100644 index 0000000..f6ba415 Binary files /dev/null and b/static/src/img/img_121_b.jpg differ diff --git a/static/src/img/img_134_b_2.jpg b/static/src/img/img_134_b_2.jpg new file mode 100644 index 0000000..1b77a6c Binary files /dev/null and b/static/src/img/img_134_b_2.jpg differ diff --git a/static/src/img/img_134_b_3.jpg b/static/src/img/img_134_b_3.jpg new file mode 100644 index 0000000..1d453ec Binary files /dev/null and b/static/src/img/img_134_b_3.jpg differ diff --git a/static/src/img/img_135_b.jpg b/static/src/img/img_135_b.jpg new file mode 100644 index 0000000..0ba3fb2 Binary files /dev/null and b/static/src/img/img_135_b.jpg differ diff --git a/static/src/img/img_137_b.jpg b/static/src/img/img_137_b.jpg new file mode 100644 index 0000000..dd872c1 Binary files /dev/null and b/static/src/img/img_137_b.jpg differ diff --git a/static/src/img/img_137_b_2.jpg b/static/src/img/img_137_b_2.jpg new file mode 100644 index 0000000..a7e6c9b Binary files /dev/null and b/static/src/img/img_137_b_2.jpg differ diff --git a/static/src/img/img_137_b_3.jpg b/static/src/img/img_137_b_3.jpg new file mode 100644 index 0000000..19bdf9c Binary files /dev/null and b/static/src/img/img_137_b_3.jpg differ diff --git a/static/src/img/img_138_b.jpg b/static/src/img/img_138_b.jpg new file mode 100644 index 0000000..01fed0f Binary files /dev/null and b/static/src/img/img_138_b.jpg differ diff --git a/static/src/img/img_138_b_2.jpg b/static/src/img/img_138_b_2.jpg new file mode 100644 index 0000000..03b8eb3 Binary files /dev/null and b/static/src/img/img_138_b_2.jpg differ diff --git a/static/src/img/img_138_b_3.jpg b/static/src/img/img_138_b_3.jpg new file mode 100644 index 0000000..5558108 Binary files /dev/null and b/static/src/img/img_138_b_3.jpg differ diff --git a/static/src/img/img_146_b.jpg b/static/src/img/img_146_b.jpg new file mode 100644 index 0000000..05ab9e2 Binary files /dev/null and b/static/src/img/img_146_b.jpg differ diff --git a/static/src/img/img_146_b_2.jpg b/static/src/img/img_146_b_2.jpg new file mode 100644 index 0000000..ea84c37 Binary files /dev/null and b/static/src/img/img_146_b_2.jpg differ diff --git a/static/src/img/img_146_b_3.jpg b/static/src/img/img_146_b_3.jpg new file mode 100644 index 0000000..3dd0383 Binary files /dev/null and b/static/src/img/img_146_b_3.jpg differ diff --git a/static/src/img/img_14_b_2.jpg b/static/src/img/img_14_b_2.jpg new file mode 100644 index 0000000..b5cf70f Binary files /dev/null and b/static/src/img/img_14_b_2.jpg differ diff --git a/static/src/img/img_14_b_3.jpg b/static/src/img/img_14_b_3.jpg new file mode 100644 index 0000000..a76b0c2 Binary files /dev/null and b/static/src/img/img_14_b_3.jpg differ diff --git a/static/src/img/img_150_b.jpg b/static/src/img/img_150_b.jpg new file mode 100644 index 0000000..e5cad6a Binary files /dev/null and b/static/src/img/img_150_b.jpg differ diff --git a/static/src/img/img_150_b_2.jpg b/static/src/img/img_150_b_2.jpg new file mode 100644 index 0000000..633138b Binary files /dev/null and b/static/src/img/img_150_b_2.jpg differ diff --git a/static/src/img/img_150_b_3.jpg b/static/src/img/img_150_b_3.jpg new file mode 100644 index 0000000..e5cad6a Binary files /dev/null and b/static/src/img/img_150_b_3.jpg differ diff --git a/static/src/img/img_151_b.jpg b/static/src/img/img_151_b.jpg new file mode 100644 index 0000000..6033ea1 Binary files /dev/null and b/static/src/img/img_151_b.jpg differ diff --git a/static/src/img/img_151_b_2.jpg b/static/src/img/img_151_b_2.jpg new file mode 100644 index 0000000..f2fae44 Binary files /dev/null and b/static/src/img/img_151_b_2.jpg differ diff --git a/static/src/img/img_151_b_3.jpg b/static/src/img/img_151_b_3.jpg new file mode 100644 index 0000000..3cdd8c1 Binary files /dev/null and b/static/src/img/img_151_b_3.jpg differ diff --git a/static/src/img/img_197_b.jpg b/static/src/img/img_197_b.jpg new file mode 100644 index 0000000..bfb9ba5 Binary files /dev/null and b/static/src/img/img_197_b.jpg differ diff --git a/static/src/img/img_197_b_2.jpg b/static/src/img/img_197_b_2.jpg new file mode 100644 index 0000000..35e2fca Binary files /dev/null and b/static/src/img/img_197_b_2.jpg differ diff --git a/static/src/img/img_197_b_3.jpg b/static/src/img/img_197_b_3.jpg new file mode 100644 index 0000000..ec64b07 Binary files /dev/null and b/static/src/img/img_197_b_3.jpg differ diff --git a/static/src/img/img_198_b.jpg b/static/src/img/img_198_b.jpg new file mode 100644 index 0000000..7a38f1e Binary files /dev/null and b/static/src/img/img_198_b.jpg differ diff --git a/static/src/img/img_198_b_2.jpg b/static/src/img/img_198_b_2.jpg new file mode 100644 index 0000000..4bbf0ec Binary files /dev/null and b/static/src/img/img_198_b_2.jpg differ diff --git a/static/src/img/img_198_b_3.jpg b/static/src/img/img_198_b_3.jpg new file mode 100644 index 0000000..f553f94 Binary files /dev/null and b/static/src/img/img_198_b_3.jpg differ diff --git a/static/src/img/img_19_b_2.jpg b/static/src/img/img_19_b_2.jpg new file mode 100644 index 0000000..0b5c1e3 Binary files /dev/null and b/static/src/img/img_19_b_2.jpg differ diff --git a/static/src/img/img_19_b_3.jpg b/static/src/img/img_19_b_3.jpg new file mode 100644 index 0000000..182bb1d Binary files /dev/null and b/static/src/img/img_19_b_3.jpg differ diff --git a/static/src/img/img_21_b_2.jpg b/static/src/img/img_21_b_2.jpg new file mode 100644 index 0000000..fd04397 Binary files /dev/null and b/static/src/img/img_21_b_2.jpg differ diff --git a/static/src/img/img_21_b_3.jpg b/static/src/img/img_21_b_3.jpg new file mode 100644 index 0000000..145e59d Binary files /dev/null and b/static/src/img/img_21_b_3.jpg differ diff --git a/static/src/img/img_4_b_2.jpg b/static/src/img/img_4_b_2.jpg new file mode 100644 index 0000000..1b2fa3e Binary files /dev/null and b/static/src/img/img_4_b_2.jpg differ diff --git a/static/src/img/img_62_b_2.jpg b/static/src/img/img_62_b_2.jpg new file mode 100644 index 0000000..c9d7693 Binary files /dev/null and b/static/src/img/img_62_b_2.jpg differ diff --git a/static/src/img/img_62_b_3.jpg b/static/src/img/img_62_b_3.jpg new file mode 100644 index 0000000..f5416d8 Binary files /dev/null and b/static/src/img/img_62_b_3.jpg differ diff --git a/static/src/img/img_63_b_2.jpg b/static/src/img/img_63_b_2.jpg new file mode 100644 index 0000000..07e2dff Binary files /dev/null and b/static/src/img/img_63_b_2.jpg differ diff --git a/static/src/img/img_63_b_3.jpg b/static/src/img/img_63_b_3.jpg new file mode 100644 index 0000000..2711346 Binary files /dev/null and b/static/src/img/img_63_b_3.jpg differ diff --git a/static/src/img/img_65_b_2.jpg b/static/src/img/img_65_b_2.jpg new file mode 100644 index 0000000..e42b6e0 Binary files /dev/null and b/static/src/img/img_65_b_2.jpg differ diff --git a/static/src/img/img_65_b_3.jpg b/static/src/img/img_65_b_3.jpg new file mode 100644 index 0000000..adcd1a0 Binary files /dev/null and b/static/src/img/img_65_b_3.jpg differ diff --git a/static/src/img/img_66_b_2.jpg b/static/src/img/img_66_b_2.jpg new file mode 100644 index 0000000..7b74756 Binary files /dev/null and b/static/src/img/img_66_b_2.jpg differ diff --git a/static/src/img/img_66_b_3.jpg b/static/src/img/img_66_b_3.jpg new file mode 100644 index 0000000..69a0059 Binary files /dev/null and b/static/src/img/img_66_b_3.jpg differ diff --git a/static/src/img/img_70_b_2.jpg b/static/src/img/img_70_b_2.jpg new file mode 100644 index 0000000..132dec1 Binary files /dev/null and b/static/src/img/img_70_b_2.jpg differ diff --git a/static/src/img/img_72_b_2.jpg b/static/src/img/img_72_b_2.jpg new file mode 100644 index 0000000..0f852b9 Binary files /dev/null and b/static/src/img/img_72_b_2.jpg differ diff --git a/static/src/img/img_72_b_3.jpg b/static/src/img/img_72_b_3.jpg new file mode 100644 index 0000000..47eecfe Binary files /dev/null and b/static/src/img/img_72_b_3.jpg differ diff --git a/static/src/img/img_74_b_2.jpg b/static/src/img/img_74_b_2.jpg new file mode 100644 index 0000000..0c2be96 Binary files /dev/null and b/static/src/img/img_74_b_2.jpg differ diff --git a/static/src/img/img_74_b_3.jpg b/static/src/img/img_74_b_3.jpg new file mode 100644 index 0000000..7d8d186 Binary files /dev/null and b/static/src/img/img_74_b_3.jpg differ diff --git a/static/src/img/img_79_b_2.jpg b/static/src/img/img_79_b_2.jpg new file mode 100644 index 0000000..f2e429c Binary files /dev/null and b/static/src/img/img_79_b_2.jpg differ diff --git a/static/src/img/img_79_b_3.jpg b/static/src/img/img_79_b_3.jpg new file mode 100644 index 0000000..263b092 Binary files /dev/null and b/static/src/img/img_79_b_3.jpg differ diff --git a/static/src/img/img_81_b_2.jpg b/static/src/img/img_81_b_2.jpg new file mode 100644 index 0000000..d3e157f Binary files /dev/null and b/static/src/img/img_81_b_2.jpg differ diff --git a/static/src/img/img_81_b_3.jpg b/static/src/img/img_81_b_3.jpg new file mode 100644 index 0000000..cac9f6a Binary files /dev/null and b/static/src/img/img_81_b_3.jpg differ diff --git a/static/src/img/img_90_b_2.jpg b/static/src/img/img_90_b_2.jpg new file mode 100644 index 0000000..dad49ca Binary files /dev/null and b/static/src/img/img_90_b_2.jpg differ diff --git a/static/src/img/img_90_b_3.jpg b/static/src/img/img_90_b_3.jpg new file mode 100644 index 0000000..d8603cc Binary files /dev/null and b/static/src/img/img_90_b_3.jpg differ diff --git a/static/src/img/img_92_b_3.jpg b/static/src/img/img_92_b_3.jpg new file mode 100644 index 0000000..4780f8e Binary files /dev/null and b/static/src/img/img_92_b_3.jpg differ diff --git a/static/src/img/img_94_b.jpg b/static/src/img/img_94_b.jpg new file mode 100644 index 0000000..1419eb5 Binary files /dev/null and b/static/src/img/img_94_b.jpg differ diff --git a/static/src/img/img_94_b_2.jpg b/static/src/img/img_94_b_2.jpg new file mode 100644 index 0000000..c12c68c Binary files /dev/null and b/static/src/img/img_94_b_2.jpg differ diff --git a/static/src/img/img_94_b_3.jpg b/static/src/img/img_94_b_3.jpg new file mode 100644 index 0000000..8e435d5 Binary files /dev/null and b/static/src/img/img_94_b_3.jpg differ diff --git a/static/src/img/img_98_b_2.jpg b/static/src/img/img_98_b_2.jpg new file mode 100644 index 0000000..f6e50c5 Binary files /dev/null and b/static/src/img/img_98_b_2.jpg differ diff --git a/static/src/js/draggable_table.js b/static/src/js/draggable_table.js new file mode 100755 index 0000000..a9c46be --- /dev/null +++ b/static/src/js/draggable_table.js @@ -0,0 +1,343 @@ +odoo.define('dss.draggable', function (require) { +"use strict"; + +console.log("imScript Drag Init") + +const ListRenderer = require('web.ListRenderer'); +const ListView = require('web.ListView'); +const EditableListRenderer = require('web.EditableListRenderer'); + +ListRenderer.include({ + init: function (parent, state, params) { + this._super.apply(this, arguments); + this.viewId = params.viewId; + console.log("imScript Drag Init") + }, + + async _renderView() { + const oldPagers = this.pagers; + let prom; + let tableWrapper; + console.log("imScript Drag") + if (this.state.count > 0 || !this.noContentHelp) { + // render a table if there are records, or if there is no no content + // helper (empty table in this case) + this.pagers = []; + + const orderedBy = this.state.orderedBy; + this.hasHandle = orderedBy.length === 0 || orderedBy[0].name === this.handleField; + this._computeAggregates(); + + const $table = $( + '' + ); + $table.toggleClass('o_list_table_grouped', this.isGrouped); + $table.toggleClass('o_list_table_ungrouped', !this.isGrouped); + // re-generate columns + var columns = this._loadListView(); + columns = columns ? columns : this.columns; + let dif = this.columns.length - columns.length; + this.columns = dif != 0 ? this.columns : columns; + + const defs = []; + this.defs = defs; + if (this.isGrouped) { + $table.append(this._renderHeader()); + $table.append(this._renderGroups(this.state.data)); + $table.append(this._renderFooter()); + + } else { + $table.append(this._renderHeader()); + $table.append(this._renderBody()); + $table.append(this._renderFooter()); + } + + // Add draggable table + this._draggable_table($table); + tableWrapper = Object.assign(document.createElement('div'), { + className: 'table-responsive', + }); + tableWrapper.appendChild($table[0]); + delete this.defs; + prom = Promise.all(defs); + } + + await Promise.all([this._super.apply(this, arguments), prom]); + + this.el.innerHTML = ""; + this.el.classList.remove('o_list_optional_columns'); + + // destroy the previously instantiated pagers, if any + oldPagers.forEach(pager => pager.destroy()); + + // append the table (if any) to the main element + if (tableWrapper) { + this.el.appendChild(tableWrapper); + if (document.body.contains(this.el)) { + this.pagers.forEach(pager => pager.on_attach_callback()); + } + if (this.optionalColumns.length) { + this.el.classList.add('o_list_optional_columns'); + this.$('table').append( + $('') + ); + this.$el.append(this._renderOptionalColumnsDropdown()); + } + if (this.selection.length) { + const $checked_rows = this.$('tr').filter( + (i, el) => this.selection.includes(el.dataset.id) + ); + $checked_rows.find('.o_list_record_selector input').prop('checked', true); + if ($checked_rows.length === this.$('.o_data_row').length) { // all rows are checked + this.$('thead .o_list_record_selector input').prop('checked', true); + } + } + } + + // display the no content helper if necessary + if (!this._hasContent() && !!this.noContentHelp) { + this._renderNoContentHelper(); + } + + }, + + _draggable_table: function($table) { + if (!$table || $table === undefined) { + return; + } + const table = $table[0]; + let draggingEle; + let draggingColumnIndex; + let placeholder; + let list; + let isDraggingStarted = false; + var self = this; + // The current position of mouse relative to the dragging element + let x = 0; + let y = 0; + + // Swap two nodes + const swap = function (nodeA, nodeB) { + const parentA = nodeA.parentNode; + const siblingA = nodeA.nextSibling === nodeB ? nodeA : nodeA.nextSibling; + + // Move `nodeA` to before the `nodeB` + nodeB.parentNode.insertBefore(nodeA, nodeB); + + // Move `nodeB` to before the sibling of `nodeA` + parentA.insertBefore(nodeB, siblingA); + }; + + // Check if `nodeA` is on the left of `nodeB` + const isOnLeft = function (nodeA, nodeB) { + // Get the bounding rectangle of nodes + const rectA = nodeA.getBoundingClientRect(); + const rectB = nodeB.getBoundingClientRect(); + + return rectA.left + rectA.width / 2 < rectB.left + rectB.width / 2; + }; + + const cloneTable = function () { + + list = document.createElement('div'); + list.classList.add('clone-list'); + table.parentNode.insertBefore(list, table); + + // Hide the original table + table.style.visibility = 'hidden'; + + // Get all cells + const originalCells = [].slice.call(table.querySelectorAll('tbody td:not(.o_list_record_selector)')); + + const originalHeaderCells = [].slice.call(table.querySelectorAll('th:not(.o_list_record_selector)')); + const numColumns = originalHeaderCells.length; + + // Loop through the header cells + originalHeaderCells.forEach(function (headerCell, headerIndex) { + const width = parseInt(window.getComputedStyle(headerCell).width); + const height = parseInt(window.getComputedStyle(headerCell).height); + // Create a new table from given row + const item = document.createElement('div'); + item.classList.add('draggable'); + + const newTable = document.createElement('table'); + newTable.setAttribute('class', 'o_list_table table table-sm table-hover table-striped'); + newTable.style.width = `${width}px`; + + // Header + const th = headerCell.cloneNode(true); + let newRow = document.createElement('tr'); + newRow.appendChild(th); + newTable.appendChild(newRow); + + const cells = originalCells.filter(function (c, idx) { + return (idx - headerIndex) % numColumns === 0; + }); + cells.forEach(function (cell) { + const newCell = cell.cloneNode(true); + newCell.style.width = `${width}px`; + newCell.style.height = `${height}px`; + newRow = document.createElement('tr'); + newRow.appendChild(newCell); + newTable.appendChild(newRow); + }); + + item.appendChild(newTable); + list.appendChild(item); + }); + console.log(list); + return list; + }; + + const mouseDownHandler = function (e) { + console.log('Handler'); + + draggingColumnIndex = [].slice.call(table.querySelectorAll('th:not(.o_list_record_selector)')).indexOf(e.target); + + // Determine the mouse position + x = e.clientX - e.target.offsetLeft; + y = e.clientY - e.target.offsetTop; + + // Attach the listeners to `document` + document.addEventListener('mousemove', mouseMoveHandler); + document.addEventListener('mouseup', mouseUpHandler); + }; + + const mouseMoveHandler = function (e) { + + if (!isDraggingStarted) { + isDraggingStarted = true; + cloneTable(); + debugger; + draggingEle = [].slice.call(list.children)[draggingColumnIndex]; + + if (typeof draggingEle === 'undefined') return; + draggingEle.classList.add('dragging'); + + // Let the placeholder take the height of dragging element + // So the next element won't move to the left or right + // to fill the dragging element space + placeholder = document.createElement('div'); + placeholder.classList.add('placeholder'); + draggingEle.parentNode.insertBefore(placeholder, draggingEle.nextSibling); + placeholder.style.width = `${draggingEle.offsetWidth}px`; + } + if (typeof draggingEle === 'undefined') return; + // Set position for dragging element + draggingEle.style.position = 'absolute'; + draggingEle.style.top = `${draggingEle.offsetTop + e.clientY - y}px`; + draggingEle.style.left = `${draggingEle.offsetLeft + e.clientX - x}px`; + + // Reassign the position of mouse + x = e.clientX; + y = e.clientY; + + // The current order + // prevEle + // draggingEle + // placeholder + // nextEle + const prevEle = draggingEle.previousElementSibling; + const nextEle = placeholder.nextElementSibling; + + // // The dragging element is above the previous element + // // User moves the dragging element to the left + if (prevEle && isOnLeft(draggingEle, prevEle)) { + // The current order -> The new order + // prevEle -> placeholder + // draggingEle -> draggingEle + // placeholder -> prevEle + swap(placeholder, draggingEle); + swap(placeholder, prevEle); + return; + } + + // The dragging element is below the next element + // User moves the dragging element to the bottom + if (nextEle && isOnLeft(nextEle, draggingEle)) { + // The current order -> The new order + // draggingEle -> nextEle + // placeholder -> placeholder + // nextEle -> draggingEle + swap(nextEle, placeholder); + swap(nextEle, draggingEle); + } + }; + + const mouseUpHandler = function () { + // // Remove the placeholder + placeholder && placeholder.parentNode && placeholder.parentNode.removeChild(placeholder); + if (typeof draggingEle === 'undefined') return; + + draggingEle.classList.remove('dragging'); + draggingEle.style.removeProperty('top'); + draggingEle.style.removeProperty('left'); + draggingEle.style.removeProperty('position'); + + // Get the end index + const endColumnIndex = [].slice.call(list.children).indexOf(draggingEle); + + isDraggingStarted = false; + + // Remove the `list` element + list.parentNode && list.parentNode.removeChild(list); + + // Move the dragged column to `endColumnIndex` + table.querySelectorAll('tr').forEach(function (row) { + const cells = [].slice.call(row.querySelectorAll('th:not(.o_list_record_selector), td:not(.o_list_record_selector)')); + draggingColumnIndex > endColumnIndex + ? cells[endColumnIndex]?.parentNode?.insertBefore( + cells[draggingColumnIndex], + cells[endColumnIndex] + ) + : cells[endColumnIndex]?.parentNode?.insertBefore( + cells[draggingColumnIndex], + cells[endColumnIndex].nextSibling + ); + + }); + // Bring back the table + table.style.removeProperty('visibility'); + + // Remove the handlers of `mousemove` and `mouseup` + document.removeEventListener('mousemove', mouseMoveHandler); + document.removeEventListener('mouseup', mouseUpHandler); + self._saveListView(draggingColumnIndex, endColumnIndex); + }; + + table.querySelectorAll('th:not(.o_list_record_selector)').forEach(function (headerCell) { + headerCell.classList.add('draggable'); + headerCell.addEventListener('mousedown', mouseDownHandler); + }); + }, + + _saveListView: function(currentIndex, newIndex) { + let key = this.state.model + '.' + this.viewId; + let savedIndex = this.columns; + let val = savedIndex[currentIndex]; + currentIndex > newIndex ? currentIndex +=1: newIndex += 1; + savedIndex.splice(newIndex, 0, val); + savedIndex.splice(currentIndex, 1); + this.columns = savedIndex; + localStorage.setItem(key, JSON.stringify(savedIndex)); + }, + + _loadListView: function() { + let key = this.state.model + '.' + this.viewId; + let savedIndex = JSON.parse(localStorage.getItem(key)); + if (!savedIndex || typeof savedIndex === 'undefined') { + return; + }; + + return savedIndex; + }, +}); + +ListView.include({ + init: function (viewInfo, params) { + this._super.apply(this, arguments); + this.rendererParams.viewId = viewInfo.view_id; + } +}); + +}); \ No newline at end of file diff --git a/static/src/js/draggable_table_new.js b/static/src/js/draggable_table_new.js new file mode 100644 index 0000000..e31d11b --- /dev/null +++ b/static/src/js/draggable_table_new.js @@ -0,0 +1,168 @@ +/** @odoo-module */ + +import { session } from "@web/session"; +import { ListRenderer } from "@web/views/list/list_renderer"; +import { patch } from "@web/core/utils/patch"; +import { browser } from "@web/core/browser/browser"; +import { useService } from "@web/core/utils/hooks"; +const {onMounted} = owl; + +/** + * Patched function to toggle record selection and add a CSS class to selected records. + * + * @param {Object} record - The record to toggle selection for. + */ +const $table = $( + '
' +); + +const table = $table[0]; + +let draggingEle; +let draggingColumnIndex; +let placeholder; +let myDragPanel +let list; +let isDraggingStarted = false; + +let x = 0; +let y = 0; + +const mouseMoveHandler = function (e) { + + console.log("moving handler !"); + + if (!isDraggingStarted) { + console.log("moving handler ! - 001 "); + isDraggingStarted = true; + //debugger; + //draggingEle = [].slice.call(list.children)[draggingColumnIndex]; + draggingEle = myDragPanel + + if (typeof draggingEle === 'undefined') return; + draggingEle.classList.add('dragging'); + + // Let the placeholder take the height of dragging element + // So the next element won't move to the left or right + // to fill the dragging element space + placeholder = document.createElement('div'); + placeholder.classList.add('placeholder'); + draggingEle.parentNode.insertBefore(placeholder, draggingEle.nextSibling); + placeholder.style.width = `${draggingEle.offsetWidth}px`; + } + if (typeof draggingEle === 'undefined') return; + // Set position for dragging element + draggingEle.style.position = 'absolute'; + draggingEle.style.top = `${draggingEle.offsetTop + e.clientY - y}px`; + draggingEle.style.left = `${draggingEle.offsetLeft + e.clientX - x}px`; + + // Reassign the position of mouse +// x = e.clientX; +// y = e.clientY; + console.log("moving "+x+" / "+y); + + // The current order + // prevEle + // draggingEle + // placeholder + // nextEle + const prevEle = draggingEle.previousElementSibling; + const nextEle = placeholder.nextElementSibling; + + // // The dragging element is above the previous element + // // User moves the dragging element to the left +// if (prevEle && isOnLeft(draggingEle, prevEle)) { + // The current order -> The new order + // prevEle -> placeholder + // draggingEle -> draggingEle + // placeholder -> prevEle +// swap(placeholder, draggingEle); +// swap(placeholder, prevEle); +// return; +// } + + // The dragging element is below the next element + // User moves the dragging element to the bottom +// if (nextEle && isOnLeft(nextEle, draggingEle)) { + // The current order -> The new order + // draggingEle -> nextEle + // placeholder -> placeholder + // nextEle -> draggingEle +// swap(nextEle, placeholder); +// swap(nextEle, draggingEle); +// } +}; + +const mouseUpHandler = function () { + // // Remove the placeholder + placeholder && placeholder.parentNode && placeholder.parentNode.removeChild(placeholder); + if (typeof draggingEle === 'undefined') return; + + draggingEle.classList.remove('dragging'); + draggingEle.style.removeProperty('top'); + draggingEle.style.removeProperty('left'); + draggingEle.style.removeProperty('position'); + + // Get the end index + const endColumnIndex = [].slice.call(list.children).indexOf(draggingEle); + + isDraggingStarted = false; + + // Remove the `list` element + list.parentNode && list.parentNode.removeChild(list); + + // Remove the handlers of `mousemove` and `mouseup` + document.removeEventListener('mousemove', mouseMoveHandler); + document.removeEventListener('mouseup', mouseUpHandler); + self._saveListView(draggingColumnIndex, endColumnIndex); +}; + +const columnclick = (e) => { + console.log("in handler !"); + + draggingColumnIndex = [].slice.call(table.querySelectorAll('th:not(.o_column_sortable)')).indexOf(e.target); + myDragPanel = e.target; +// debugger; + console.log("in handler !" + draggingColumnIndex); + + // Determine the mouse position +// x = e.clientX - e.target.offsetLeft; +// y = e.clientY - e.target.offsetTop; + + x = e.clientX; + y = e.clientY; + + // Attach the listeners to `document` + window.addEventListener('mousemove', mouseMoveHandler); + window.addEventListener('mouseup', mouseUpHandler); + //isDraggingStarted = true; + +}; + +patch(ListRenderer.prototype, 'DigitalSignage/static/src/js/draggable_table_new.js', { + setup() { + console.log("List view started!"); + this._super.apply(this, arguments); + + window.addEventListener("mousedown", columnclick); + }, + + onClickSortColumn(column) { + console.log("in getColumns") + this._super.apply(this, arguments); + }, + + toggleRecordSelection(record) { + console.log("imScript Drag") + var self = this; + this._super.apply(this, arguments); + var selectedRecord = $(event.target).closest('tr') + if ($(event.target).prop('checked')) { + selectedRecord.addClass('selected_record'); + } else { + selectedRecord.removeClass('selected_record') + } + } + +}); + diff --git a/static/src/js/form_button.js b/static/src/js/form_button.js index f080c18..80dde55 100644 --- a/static/src/js/form_button.js +++ b/static/src/js/form_button.js @@ -8,16 +8,50 @@ var rpc = require('web.rpc') export class configListController extends ListController { setup() { - super.setup(); + super.setup(); + // var table=document.getElementsByClassName('o_list_table'); + // var headerList= table.children[0].children[0].children;; + // alert(headerList.length) +// for(var l=1;l - +
+
+ -
-
- +
+
+ -
-
- +
+
+ -
+
-
-
- -
-
-
-
- +
+
+
+

gep.Start

+
+
+
+
+

Zuarb.

+
+
+
+
+

Korr.Abz.

+
+
+
+
+

Freig.

+
+
+

Freig.

+
+
+

Freig. bis

+
+
+

Freig. bis

+
+
+
+
+
+
+

Frist :

+
+
+
+
+
+
+
diff --git a/views/dss_importinvoicelist.xml b/views/dss_importinvoicelist.xml new file mode 100644 index 0000000..fc8214a --- /dev/null +++ b/views/dss_importinvoicelist.xml @@ -0,0 +1,114 @@ + + + + + dss_importinvoicelist_form + dss.importinvoicelist + +
+
+
+ + + + + + +
+
+
+ + + + + + + + +
+
+ + + +
+ +
+
+ + + + dss_importinvoicelist_tree + dss.importinvoicelist + + + + + + + + + + + + + DigitalSignage Import Verträge + ir.actions.act_window + dss.importinvoicelist + tree,form + +

+ Keine Rechnungslisten importiert. +

+

+ Klicke auf importieren. +

+
+
+ + + dss_importinvoicelist_popup + dss.importinvoicelist + +
+ + +
+

+ +

+
+
+
+ +
+
+ + + Dynamic Popup + ir.actions.act_window + form + + new + {'dynamic_message': 'This is a dynamically generated message!'} + + + + +
\ No newline at end of file diff --git a/views/dss_invoices.xml b/views/dss_invoices.xml new file mode 100644 index 0000000..26ca7ef --- /dev/null +++ b/views/dss_invoices.xml @@ -0,0 +1,76 @@ + + + + + dss_invoice_form + dss.invoices + +
+
+
+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + + dss_invoice_tree + dss.invoices + + + + + + + + + + + + + + + + + + + DigitalSignage Invoice + ir.actions.act_window + dss.invoices + tree,form + +

+ Keine Rechnungen importiert. +

+

+ Klicke auf importieren. +

+
+
+ +
\ No newline at end of file diff --git a/views/dss_marker.xml b/views/dss_marker.xml new file mode 100644 index 0000000..7269dbd --- /dev/null +++ b/views/dss_marker.xml @@ -0,0 +1,53 @@ + + + + + dss_marker_form + dss.marker + + +
+ + + + + + + +
+ + + +
+ +
+
+ + + dss_marker_tree + dss.marker + + + + + + + + + + + + DigitalSignage Datensatz-Marker + ir.actions.act_window + dss.marker + tree,form + {} + +

+ Neuen Standardtext erstellen +

+
+
+ + +
diff --git a/views/dss_projects.xml b/views/dss_projects.xml index 742f692..b3cff7d 100755 --- a/views/dss_projects.xml +++ b/views/dss_projects.xml @@ -32,6 +32,9 @@ dss.projects
+
+
@@ -52,7 +55,7 @@
-
@@ -64,6 +67,11 @@ + + + + +
@@ -84,6 +92,21 @@
+
+
+ + + +
+
+
+
+ + + + +
+
@@ -157,9 +180,21 @@
- - - + + + + + + + + + + + + + + +
@@ -178,10 +213,12 @@ dss.projects - + - + + + @@ -237,9 +274,11 @@
-
- -
+
+ +
+
+
@@ -280,7 +319,7 @@ - + @@ -292,6 +331,11 @@ + + + + + @@ -306,7 +350,21 @@ DigitalSignage Projekte ir.actions.act_window dss.projects - kanban,form,tree,calendar + kanban,form,tree,calendar,activity + + {'search_default_actual_projects': 1} + +

+ Fuege ein System ein ! +

+
+ + + + DigitalSignage Projekte + ir.actions.act_window + dss.projects + tree,kanban,form,calendar,activity {'search_default_actual_projects': 1} diff --git a/views/dss_settings.xml b/views/dss_settings.xml index cfcb5ff..e0cf1bf 100755 --- a/views/dss_settings.xml +++ b/views/dss_settings.xml @@ -13,6 +13,22 @@ + + dss_viewsettings_tree + dss.viewsettings + + + + + + + + + + + + + dss_settings_form dss.settings @@ -89,6 +105,30 @@ + +
+ + + + +
+
+ +
+ + + + + +
+
+ +
+ + + +
+
@@ -107,4 +147,16 @@
+ + DigitalSignage ViewSettings + ir.actions.act_window + tree,form + dss.viewsettings + {} + +

+

+
+
+ diff --git a/views/dss_systemtypen.xml b/views/dss_systemtypen.xml index 5123283..e19402a 100755 --- a/views/dss_systemtypen.xml +++ b/views/dss_systemtypen.xml @@ -31,11 +31,15 @@ + + " + + diff --git a/views/dss_trigger_action_groups.xml b/views/dss_trigger_action_groups.xml new file mode 100644 index 0000000..2a2a304 --- /dev/null +++ b/views/dss_trigger_action_groups.xml @@ -0,0 +1,62 @@ + + + + + dss_trigger_action_group_form + dss.triggeractions.groups + + +
+ + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + dss_trigger_action_group_tree + dss.triggeractions.groups + + + + + + + + + + + DigitalSignage Triggeraktion Gruppen + ir.actions.act_window + dss.triggeractions.groups + tree,form + {} + +

+ Neuen Standardtext erstellen +

+
+
+ +
diff --git a/views/dss_trigger_actions.xml b/views/dss_trigger_actions.xml index a150287..c2caad1 100755 --- a/views/dss_trigger_actions.xml +++ b/views/dss_trigger_actions.xml @@ -9,11 +9,21 @@
- + + + + + + - + + + + + + @@ -24,23 +34,74 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + @@ -79,4 +140,13 @@
+ + TriggerAktion sofort auslösen + + + form + code + action = records.exectriggeraction() + + diff --git a/views/dss_trigger_conditions.xml b/views/dss_trigger_conditions.xml new file mode 100755 index 0000000..26f1639 --- /dev/null +++ b/views/dss_trigger_conditions.xml @@ -0,0 +1,67 @@ + + + + + dss_triggerconditions_form + dss.triggerconditions + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + dss_triggerconditions_tree + dss.triggerconditions + + + + + + + + + + DigitalSignage TriggerBedingungen + ir.actions.act_window + dss.triggerconditions + tree,form + {} + +

+ Neuen Standardtext erstellen +

+
+
+ +
diff --git a/views/dss_trigger_execute.xml b/views/dss_trigger_execute.xml new file mode 100755 index 0000000..9ef8b72 --- /dev/null +++ b/views/dss_trigger_execute.xml @@ -0,0 +1,47 @@ + + + + + dss_triggerexecute_form + dss.triggermodel.execute + + +
+ + + + + + + + +
+
+ + + dss_triggerexecute_tree + dss.triggermodel.execute + + + + + + + + + + + + DigitalSignage Trigger Ausführungen + ir.actions.act_window + dss.triggermodel.execute + tree,form + {} + +

+ Neuen Standardtext erstellen +

+
+
+ +
diff --git a/views/dss_trigger_groups.xml b/views/dss_trigger_groups.xml index 1752c8f..475ee2a 100644 --- a/views/dss_trigger_groups.xml +++ b/views/dss_trigger_groups.xml @@ -8,19 +8,28 @@
- - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +
@@ -57,4 +66,13 @@ + + Triggergruppe sofort auslösen + + + form + code + action = records.exectrigger() + + diff --git a/views/dss_triggertypes.xml b/views/dss_triggertypes.xml index 0ad486b..25a2c59 100755 --- a/views/dss_triggertypes.xml +++ b/views/dss_triggertypes.xml @@ -13,28 +13,59 @@ - + + + + + - + + + + + + - - - + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + - - - - + + + + diff --git a/views/dss_web_contracts.xml b/views/dss_web_contracts.xml new file mode 100755 index 0000000..fde9491 --- /dev/null +++ b/views/dss_web_contracts.xml @@ -0,0 +1,285 @@ + + + + + DigitalSignage Alle Web_Vertraege + ir.actions.act_window + dss.web_contracts + tree,form,activity + +

+ No Contracts/Clients found. Let's create one! +

+

+ Keep track of the progress of your contracts from creation to completion.
+ Collaborate efficiently by chatting in real-time or via email. +

+
+
+ + + dss_main_web_contracts_tree + dss.web_contracts + + + + + + + + + + + + + + + + + + + + + + + + + + + + dss_main_web_contracts_form + dss.web_contracts + + + +
+
+
+

+ +

+
+ +
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+
+
+
+
+
+ + + +
+
+ + + +
+
+ + + + + + + + + +
+
+ + + +
+
+ + + + +
+
+ + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+
+
+
+ + + + +
+ + + + + +
+
+ + + +
+ +
+
+ + + + DigitalSignage Werbe Themenkanäle + ir.actions.act_window + dss.contracts_ads_topics + tree + +

+ No Contracts/Clients found. Let's create one! +

+

+ Keep track of the progress of your contracts from creation to completion.
+ Collaborate efficiently by chatting in real-time or via email. +

+
+
+ + + dss_main_contracts_ads_topics_tree + dss.contracts_ads_topics + + + + + + + + + + +
diff --git a/views/mainsystem_view.xml b/views/mainsystem_view.xml index a418403..f2934c9 100755 --- a/views/mainsystem_view.xml +++ b/views/mainsystem_view.xml @@ -49,6 +49,7 @@ + @@ -64,7 +65,10 @@ + + + diff --git a/views/menu.xml b/views/menu.xml index d158530..7935c14 100755 --- a/views/menu.xml +++ b/views/menu.xml @@ -1,87 +1,190 @@ - - - - - + + - - - - + sequence="10"/> - + sequence="11"/> - + + - + sequence="21"/> + + + + + + + + + + + + + sequence="12"/> + + + + + + + + + + + + + + + + + + + + + + + + + + sequence="55"/> + + + + + + + \ No newline at end of file