Add odex25_transactions
This commit is contained in:
parent
3a3f834c54
commit
78a2e864a6
|
|
@ -1,2 +1,2 @@
|
|||
# odex25-standard-moduless
|
||||
# odex25-standard-modules
|
||||
This Repo contains general standard modules for all projects.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="Jinja2" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="E265" />
|
||||
<option value="E501" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N801" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/odex25_transactions.iml" filepath="$PROJECT_DIR$/.idea/odex25_transactions.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
*pip install arabic-reshaper
|
||||
*pip install python-bidi
|
||||
pip install python-barcode
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from . import models
|
||||
from . import wizards
|
||||
from . import controllers
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odex - Communications Management System.
|
||||
# Copyright (C) 2020 Expert Co. Ltd. (<http://exp-sa.com>).
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name' : 'C.M. Entity Sync',
|
||||
'version' : '0.1',
|
||||
'sequence' : 4,
|
||||
'author' : 'Expert Co. Ltd.',
|
||||
'category' : 'Odex25-Transactions/Odex25-Transactions',
|
||||
'summary' : 'Correspondence Management, Entity Sync',
|
||||
'description' : """
|
||||
Odex - Correspondence Management, Entity Syncronization
|
||||
========================================================
|
||||
|
||||
Intercompanies entity syncronization
|
||||
""",
|
||||
'website': 'http://www.exp-sa.com',
|
||||
'depends': ['exp_transaction_documents'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
# data
|
||||
'data/data.xml',
|
||||
# views
|
||||
'views/entity_view.xml',
|
||||
'views/settings_view.xml',
|
||||
# wizards
|
||||
'wizards/inter_entity_wizard.xml',
|
||||
# actions amd menus
|
||||
'views/actions_and_menus.xml',
|
||||
],
|
||||
'qweb' : [
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': False,
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from . import sync
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
import logging
|
||||
import datetime
|
||||
import base64
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo import models, api, fields, _,exceptions,SUPERUSER_ID
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Sync(http.Controller):
|
||||
@http.route('/cm/sync/broadcast', type='json', auth='public', methods=['POST'])
|
||||
def add_new(self, **kw):
|
||||
keys = [
|
||||
'url',
|
||||
'name',
|
||||
'code',
|
||||
'key',
|
||||
'auth',
|
||||
]
|
||||
for k in keys:
|
||||
if not kw.get(k, False):
|
||||
return {
|
||||
'error': 'Bad Request 1',
|
||||
}
|
||||
inter_entity = request.env['cm.inter_entity'].sudo()
|
||||
if not inter_entity.authenticate(kw.get('auth', '')):
|
||||
return {
|
||||
'error': 'Bad Request 2',
|
||||
'req': kw,
|
||||
}
|
||||
data = {
|
||||
'url': kw.get('url', ''),
|
||||
'name': kw.get('name', ''),
|
||||
'code': kw.get('code', ''),
|
||||
'uuid': kw.get('key', ''),
|
||||
}
|
||||
entities = inter_entity.add_new(data)
|
||||
return {
|
||||
'success': True,
|
||||
'entities': entities,
|
||||
}
|
||||
|
||||
@http.route('/cm/sync/update_from', type='json', auth='public', methods=['POST'])
|
||||
def update_from(self, **kw):
|
||||
keys = [
|
||||
'key',
|
||||
'auth',
|
||||
]
|
||||
for k in keys:
|
||||
if not kw.get(k, False):
|
||||
return {
|
||||
'error': 'Bad Request 1',
|
||||
}
|
||||
inter_entity = request.env['cm.inter_entity'].sudo()
|
||||
if not inter_entity.authenticate(kw.get('auth', '')):
|
||||
return {
|
||||
'error': 'Bad Request 2',
|
||||
'req': kw,
|
||||
}
|
||||
return {
|
||||
'success': True,
|
||||
'entities': inter_entity.get_entities()
|
||||
}
|
||||
data = {
|
||||
'url': kw.get('url', ''),
|
||||
'name': kw.get('name', ''),
|
||||
'code': kw.get('code', ''),
|
||||
'uuid': kw.get('key', ''),
|
||||
}
|
||||
entities = inter_entity.add_new(data)
|
||||
return {
|
||||
'success': True,
|
||||
'entities': entities,
|
||||
}
|
||||
|
||||
@http.route('/cm/sync/new_key', type='json', auth='public', methods=['POST'])
|
||||
def new_key(self, **kw):
|
||||
keys = [
|
||||
'old',
|
||||
'key',
|
||||
'auth',
|
||||
]
|
||||
for k in keys:
|
||||
if not kw.get(k, False):
|
||||
return {
|
||||
'error': 'Bad Request 1',
|
||||
}
|
||||
inter_entity = request.env['cm.inter_entity'].sudo()
|
||||
if not inter_entity.authenticate(kw.get('auth', '')):
|
||||
return {
|
||||
'error': 'Bad Request 2',
|
||||
}
|
||||
old = inter_entity.search([('uuid', '=', kw.get('old'))], limit=1)
|
||||
if len(old):
|
||||
data = {
|
||||
'uuid': kw.get('key'),
|
||||
'code': kw.get('key').split('-')[0],
|
||||
}
|
||||
old.write(data)
|
||||
return {
|
||||
'success': True,
|
||||
}
|
||||
|
||||
@http.route('/cm/sync/update_entity', type='json', auth='public', methods=['POST'])
|
||||
def update_entity(self, **kw):
|
||||
keys = [
|
||||
'data',
|
||||
'auth',
|
||||
]
|
||||
for k in keys:
|
||||
if not kw.get(k, False):
|
||||
return {
|
||||
'error': 'Bad Request 1',
|
||||
}
|
||||
inter_entity = request.env['cm.inter_entity'].sudo()
|
||||
inter_entity_set = request.env['cm.inter_entity.sync'].sudo()
|
||||
if not inter_entity.authenticate(kw.get('auth', '')):
|
||||
return {
|
||||
'error': 'Bad Request 2',
|
||||
}
|
||||
data = kw['data']
|
||||
key = data['key']
|
||||
entity = inter_entity.search([('uuid', '=', key)], limit=1)
|
||||
ecode = data['details']['code']
|
||||
is_new = data['details'].get('is_new', False)
|
||||
if len(entity):
|
||||
en = request.env['cm.entity'].sudo().search(
|
||||
[('inter_entity_code', '=', ecode), ('inter_entity_id', '=', entity.id)])
|
||||
if len(en):
|
||||
d = data['details']['data']
|
||||
d['broadcasted'] = True
|
||||
en.write(d)
|
||||
elif is_new:
|
||||
d = data['details']['data']
|
||||
dd = {
|
||||
'name': d.get('name', ''),
|
||||
# 'code': d.get('code', ''),
|
||||
'type': 'external',
|
||||
'is_inter_entity': True,
|
||||
'inter_entity_code': d.get('inter_entity_code', ''),
|
||||
'inter_entity_id': entity.id,
|
||||
}
|
||||
request.env['cm.entity'].sudo().create(dd)
|
||||
else:
|
||||
return {
|
||||
'error': 'No Record'
|
||||
}
|
||||
return {
|
||||
'success': True,
|
||||
}
|
||||
|
||||
@http.route('/cm/sync/push_new', type='json', auth='public', methods=['POST'])
|
||||
def push_new(self, **kw):
|
||||
keys = [
|
||||
'data',
|
||||
'auth',
|
||||
]
|
||||
for k in keys:
|
||||
if not kw.get(k, False):
|
||||
return {
|
||||
'error': 'Bad Request 1',
|
||||
}
|
||||
inter_entity = request.env['cm.inter_entity'].sudo()
|
||||
if not inter_entity.authenticate(kw.get('auth', '')):
|
||||
return {
|
||||
'error': 'Bad Request 2',
|
||||
}
|
||||
data = kw['data']
|
||||
key = data['key']
|
||||
entity = inter_entity.search([('uuid', '=', key)], limit=1)
|
||||
|
||||
if len(entity):
|
||||
|
||||
d = data['data']
|
||||
dd = {
|
||||
'name': d.get('name', ''),
|
||||
# 'code': d.get('code', ''),
|
||||
'type': 'external',
|
||||
'is_inter_entity': True,
|
||||
'inter_entity_code': d.get('inter_entity_code', ''),
|
||||
'inter_entity_id': entity.id,
|
||||
}
|
||||
try:
|
||||
request.env['cm.entity'].sudo().with_context(
|
||||
broacasted=True).create(dd)
|
||||
return {
|
||||
'success': True,
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'error': 'No Record'
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'error': 'No Record'
|
||||
}
|
||||
return {
|
||||
'success': True,
|
||||
}
|
||||
|
||||
@http.route('/cm/sync/send_transaction', type='json', auth='public', methods=['POST'])
|
||||
def send_transaction(self, **kw):
|
||||
keys = [
|
||||
'data',
|
||||
'code',
|
||||
'key',
|
||||
'auth',
|
||||
]
|
||||
for k in keys:
|
||||
if not kw.get(k, False):
|
||||
return {
|
||||
'error': 'Bad Request 1',
|
||||
}
|
||||
inter_entity = request.env['cm.inter_entity'].sudo()
|
||||
Entity = request.env['cm.entity'].sudo()
|
||||
if not inter_entity.authenticate(kw.get('auth', '')):
|
||||
return {
|
||||
'error': 'Bad Request 2',
|
||||
}
|
||||
data = kw['data']
|
||||
code = kw['code']
|
||||
key = kw['key']
|
||||
auth = kw['auth']
|
||||
from_id = data['from_id']
|
||||
ie = inter_entity.search([('uuid', '=', auth)], limit=1)
|
||||
extie = inter_entity.search([('uuid', '=', key)], limit=1)
|
||||
setting = inter_entity.get_settings()
|
||||
if not len(ie) or not len(extie):
|
||||
return {
|
||||
'error': 'No Record 1'
|
||||
}
|
||||
if not from_id:
|
||||
from_id = Entity.search([('is_master_entity', '=', True),
|
||||
('type', '=', 'external'), ('inter_entity_id', '=', extie.id)], limit=1)
|
||||
if not len(from_id):
|
||||
return {
|
||||
'error': 'No Record 2'
|
||||
}
|
||||
else:
|
||||
from_id = Entity.search([('inter_entity_code', '=', from_id), (
|
||||
'type', '=', 'external'), ('inter_entity_id', '=', extie.id)], limit=1)
|
||||
if not len(from_id):
|
||||
return {
|
||||
'error': 'No Record 3'
|
||||
}
|
||||
entity = Entity.search([('inter_entity_code', '=', code),('type', '=', 'unit')], limit=1)
|
||||
if len(entity) > 0 and len(from_id) > 0:
|
||||
Incoming = request.env['incoming.transaction'].sudo()
|
||||
d = data
|
||||
d['from_id'] = from_id.id
|
||||
d['inter_entity_id'] = extie.id
|
||||
d['important_id'] = setting.important_id.id
|
||||
d['subject_type_id'] = setting.subject_type_id.id
|
||||
if len(entity.secretary_id):
|
||||
d['employee_id'] = entity.secretary_id.id
|
||||
d['preparation_id'] = entity.id
|
||||
else:
|
||||
d['employee_id'] = setting.employee_id.id
|
||||
d['preparation_id'] = setting.id
|
||||
d['to_ids'] = [(4, entity.id), ]
|
||||
# if entity.body:
|
||||
# d['body'] = entity.body
|
||||
d['due_date'] = fields.date.today()
|
||||
attachment_rule_ids = d.get('attachment_rule_ids')
|
||||
d.pop('attachment_rule_ids')
|
||||
inc = Incoming.create(d)
|
||||
for attachment in attachment_rule_ids:
|
||||
attachement_rule = request.env['cm.attachment.rule'].sudo().create({
|
||||
'employee_id': entity.secretary_id.id if len(entity.secretary_id) else setting.employee_id.id,
|
||||
'entity_id': entity.id,
|
||||
'file_save': attachment['file_save'],
|
||||
'attachment_filename': attachment['attachment_filename'],
|
||||
'incoming_transaction_id': inc.id if inc.id else False,
|
||||
'date': attachment['date'],
|
||||
'description': attachment['description'],
|
||||
})
|
||||
attachment_data = {
|
||||
'name': attachment['attachment_filename'],
|
||||
'datas_fname': attachment['attachment_filename'],
|
||||
'datas': attachment['file_save'],
|
||||
'res_model': 'cm.attachment.rule',
|
||||
'res_id': attachement_rule.id,
|
||||
}
|
||||
request.env['ir.attachment'].sudo().create(attachment_data)
|
||||
inc.preparation_id = inc.entity_id
|
||||
# notification system and mailing
|
||||
employee = inc.from_id
|
||||
subj = _('Message Has been send !')
|
||||
msg = _(u'{} ← {}.{}').format(employee and employee.name or '#',
|
||||
u' / '.join([k.name for k in inc.to_ids]),
|
||||
u'<a href="%s" >رابط المعاملة</a> ' % (inc.get_url()))
|
||||
partner_ids = []
|
||||
for partner in inc.to_ids:
|
||||
if partner.type == 'unit':
|
||||
partner_ids.append(partner.secretary_id.user_id.partner_id.id)
|
||||
elif partner.type == 'employee':
|
||||
partner_ids.append(partner.user_id.partner_id.id)
|
||||
# thread_obj = request.env['mail.thread']
|
||||
# thread_obj.message_post(type="notification", subject=subj, body=msg,
|
||||
# partner_ids=partner_ids,
|
||||
# subtype="mail.mt_comment")
|
||||
# inc.send_message(template='exp_transaction_documents.incoming_notify_send_send_email')
|
||||
else:
|
||||
return {
|
||||
'error': 'No Record 4'
|
||||
}
|
||||
return {
|
||||
'success': True,
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<openerp>
|
||||
<data>
|
||||
<record id="sync_settings" model="cm.inter_entity.sync"></record>
|
||||
|
||||
<!-- <record id="seq_type_cm_inter_entity" model="ir.sequence.type">-->
|
||||
<!-- <field name="name">Entities</field>-->
|
||||
<!-- <field name="code">cm.inter.entity</field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<record id="seq_cm_inter_entity" model="ir.sequence">
|
||||
<field name="name">Inter-Entities Seq</field>
|
||||
<field name="code">cm.inter.entity</field>
|
||||
<field name="prefix"></field>
|
||||
<field name="suffix"></field>
|
||||
<field name="padding">6</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * cm_entity_sync_odex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 11.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-05-16 03:24+0000\n"
|
||||
"PO-Revision-Date: 2020-05-16 03:24+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,help:cm_entity_sync_odex.field_cm_entity_is_inter_entity
|
||||
#: model:ir.model.fields,help:cm_entity_sync_odex.field_cm_entity_is_master_entity
|
||||
msgid "\n"
|
||||
" If checked, this entity will be syncronized by other entities in the group.\n"
|
||||
" "
|
||||
msgstr "\n"
|
||||
" اذا تمّ اختياره، سيتم مشاركة المؤسسة مع بقية المؤسسات في المجموعة.\n"
|
||||
" "
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/models/entity.py:278
|
||||
#: code:addons/cm_entity_sync_odex/models/entity.py:280
|
||||
#, python-format
|
||||
msgid "Access Error"
|
||||
msgstr "ليس لديك صلاحية !"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_activated
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_sync_config
|
||||
msgid "Activate Syncronization"
|
||||
msgstr "تفعيل نظام المزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_broadcast
|
||||
msgid "Broadcast"
|
||||
msgstr "مزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/wizards/wizards.py:34
|
||||
#, python-format
|
||||
msgid "Broadcast Error !Error While Broadcast new Server, please check server key and url."
|
||||
msgstr "خطا في المزامنة ! خطا عند مزامنة مخدم الجديد , الرجاء التأكد من عنوان الويب او مفتاح المخدم."
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_update_wizard
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_wizard
|
||||
msgid "Cancel"
|
||||
msgstr "إلغاء"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_code
|
||||
msgid "Code"
|
||||
msgstr "رمز"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_create_uid
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_create_uid
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_create_uid
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_create_uid
|
||||
msgid "Created by"
|
||||
msgstr "أنشئ بواسطة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_create_date
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_create_date
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_create_date
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_create_date
|
||||
msgid "Created on"
|
||||
msgstr "أنشئ في"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_server_id
|
||||
msgid "Current Server"
|
||||
msgstr "السيرفر (النظام) الحالي"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_employee_id
|
||||
msgid "Default Created By"
|
||||
msgstr "مدخل المعاملة الافتراضي"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_important_id
|
||||
msgid "Default Important Degree"
|
||||
msgstr "درجة الأهمية الافتراضية"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_subject_type_id
|
||||
msgid "Default Transaction Type"
|
||||
msgstr "نوع المعاملة الافتراضي"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_name
|
||||
msgid "Description"
|
||||
msgstr "الوصف"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_display_name
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_display_name
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_display_name
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_display_name
|
||||
msgid "Display Name"
|
||||
msgstr "الاسم المعروض"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_document_id
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_document_id
|
||||
msgid "Document"
|
||||
msgstr "مستند"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_entities
|
||||
msgid "Entities"
|
||||
msgstr "العناوين و الجهات"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model,name:cm_entity_sync_odex.model_cm_inter_entity_sync
|
||||
msgid "Entity Syncronization"
|
||||
msgstr "الوحدات المتزامنه"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_wizard
|
||||
msgid "Generate"
|
||||
msgstr "توليــد"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_sync_config
|
||||
msgid "Generate Key"
|
||||
msgstr "توليد مفتاح مزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/models/settings.py:36
|
||||
#, python-format
|
||||
msgid "Generate new Key"
|
||||
msgstr "توليد مفتاح مزامنة جديدة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_id
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_id
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_id
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_id
|
||||
msgid "ID"
|
||||
msgstr "المعرف"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_sync_config
|
||||
msgid "Inter Entities"
|
||||
msgstr "المؤسسات المتزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_incoming_transaction_inter_entity_id
|
||||
msgid "Inter Entity"
|
||||
msgstr "مؤسسة متزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.actions.act_window,name:cm_entity_sync_odex.cm_inter_entity_sync_action
|
||||
#: model:ir.ui.menu,name:cm_entity_sync_odex.cm_inter_entity_sync_menu
|
||||
msgid "Inter Entity Sync"
|
||||
msgstr "إعدادات المؤسسات المتزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.cm_inter_entity_tree
|
||||
msgid "Inter-Entities"
|
||||
msgstr "المؤسسات المتزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_entity_inter_entity_code
|
||||
msgid "Inter-Entities Code"
|
||||
msgstr "رمز التزامن"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_entity_inter_entity_id
|
||||
msgid "Inter-Entities Ref"
|
||||
msgstr "مرجع المؤسسة المتزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.cm_inter_entity_form
|
||||
msgid "Inter-Entity"
|
||||
msgstr "مؤسسة متزامنة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_entity_is_inter_entity
|
||||
msgid "Is Inter-Entity ?"
|
||||
msgstr "مؤسسة متزامنة ؟"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_entity_is_master_entity
|
||||
msgid "Is Master-Entity ?"
|
||||
msgstr "مؤسسة متزمنة رئيسية ؟"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity___last_update
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync___last_update
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard___last_update
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard___last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr "آخر تعديل في"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_write_uid
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_write_uid
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_write_uid
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr "آخر تحديث بواسطة"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_write_date
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_write_date
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_write_date
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr "آخر تحديث في"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_primary_id
|
||||
msgid "Main Server"
|
||||
msgstr "الخادم الرئيسي"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/controllers/sync.py:290
|
||||
#, python-format
|
||||
msgid "Message Has been send !"
|
||||
msgstr "تم ارسال الرساله"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_uuid
|
||||
msgid "Secret Key"
|
||||
msgstr "الرمز السري"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_server_key
|
||||
msgid "Server Key"
|
||||
msgstr "مفتاح التزامن للسيرفر"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_url
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_server_url
|
||||
msgid "Server URL"
|
||||
msgstr "رابط السيرفر"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/models/entity.py:165
|
||||
#: code:addons/cm_entity_sync_odex/models/entity.py:266
|
||||
#: code:addons/cm_entity_sync_odex/models/entity.py:294
|
||||
#, python-format
|
||||
msgid "Sync Error Cannot Syncronize new key to Server {}, URL \"{}\""
|
||||
msgstr "مشكلة في التزامن , غير قادر على مزامنة المفتاح الجديد Server {}, URL \"{}\""
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/models/entity.py:242
|
||||
#, python-format
|
||||
msgid "Sync Error Cannot send Transaction to server {}"
|
||||
msgstr "مشكلة تزامن , لا يمكن ارسال المعاملة لمخدم {}"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/models/entity.py:150
|
||||
#, python-format
|
||||
msgid "Sync ErrorCannot Syncronize new key to Server {}, URL \"{}\""
|
||||
msgstr "مشكلة في التزامن , غير قادر على مزامنة المفتاح الجديد Server {}, URL \"{}\""
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_sync_key
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_key
|
||||
msgid "Sync Key"
|
||||
msgstr "مفتاح التزامن"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_incoming_transaction_syncronized
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_outgoing_transaction_syncronized
|
||||
msgid "Syncronized ?"
|
||||
msgstr "متزامن ؟"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model,name:cm_entity_sync_odex.model_cm_entity
|
||||
msgid "Transactions Contacts"
|
||||
msgstr "Transactions Contacts"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_update_wizard
|
||||
msgid "Update"
|
||||
msgstr "تحديث الخوادم"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/models/settings.py:63
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_sync_config
|
||||
#, python-format
|
||||
msgid "Update From ..."
|
||||
msgstr "تحديث من ..."
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_server_id
|
||||
msgid "Update Server"
|
||||
msgstr "خادم التحديث"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/models/entity.py:280
|
||||
#, python-format
|
||||
msgid "You cannot change syncronized entity data !"
|
||||
msgstr "لا يمكنك تعديل بيانات المؤسسات المتزامنة !"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model,name:cm_entity_sync_odex.model_cm_inter_entity_update_wizard
|
||||
msgid "cm.inter.entity.update.wizard"
|
||||
msgstr "cm.inter.entity.update.wizard"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model,name:cm_entity_sync_odex.model_cm_inter_entity_wizard
|
||||
msgid "cm.inter.entity.wizard"
|
||||
msgstr "cm.inter.entity.wizard"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model,name:cm_entity_sync_odex.model_cm_inter_entity
|
||||
msgid "cm.inter_entity"
|
||||
msgstr "cm.inter_entity"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model,name:cm_entity_sync_odex.model_incoming_transaction
|
||||
msgid "incoming Transaction"
|
||||
msgstr "معاملات الوارد الخارجي"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_update_wizard
|
||||
#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_wizard
|
||||
msgid "or"
|
||||
msgstr "أو"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: model:ir.model,name:cm_entity_sync_odex.model_outgoing_transaction
|
||||
msgid "outgoing Transaction"
|
||||
msgstr "معاملات الصادر الخارجي"
|
||||
|
||||
#. module: cm_entity_sync_odex
|
||||
#: code:addons/cm_entity_sync_odex/controllers/sync.py:291
|
||||
#, python-format
|
||||
msgid "{} ← {}.{}"
|
||||
msgstr "{} ← {}.{}"
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from . import entity
|
||||
from . import settings
|
||||
from . import outgoing
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
import logging
|
||||
import uuid
|
||||
import requests
|
||||
# from odoo import _, api, exceptions, fields, models
|
||||
from odoo import models, api, fields,_
|
||||
from odoo.exceptions import Warning,AccessError
|
||||
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EntityMatrix(models.Model):
|
||||
_name = 'cm.inter_entity'
|
||||
|
||||
code = fields.Char(string='Code')
|
||||
name = fields.Char(string='Description')
|
||||
url = fields.Char(string='Server URL')
|
||||
uuid = fields.Char(string='Secret Key')
|
||||
|
||||
@api.model
|
||||
def generate_key(self):
|
||||
key = uuid.uuid4()
|
||||
return str(key)
|
||||
|
||||
@api.model
|
||||
def broadcast(self, key=None, url=None, new_key=None):
|
||||
if url.endswith('/'):
|
||||
url = u'{}{}'.format(url[:-1], '/cm/sync/broadcast')
|
||||
else:
|
||||
url = u'{}{}'.format(url, '/cm/sync/broadcast')
|
||||
code = new_key.split('-')[0]
|
||||
company_name = self.env.user.company_id.name
|
||||
new_url = self.env['ir.config_parameter'].sudo(
|
||||
).get_param('web.base.url')
|
||||
new_url = new_url.replace('http://', 'http://')
|
||||
data = {
|
||||
'code': code,
|
||||
'name': company_name,
|
||||
'url': new_url,
|
||||
'key': new_key,
|
||||
'auth': key,
|
||||
}
|
||||
try:
|
||||
json = {
|
||||
'jsonrpc': '2.0',
|
||||
'method': 'call',
|
||||
'id': None,
|
||||
'params': data,
|
||||
}
|
||||
result = requests.post(url, json=json)
|
||||
r = result.json()
|
||||
if 'success' not in r.get('result', {}):
|
||||
_logger.error(r)
|
||||
return False
|
||||
entities = r.get('result', {}).get('entities', [])
|
||||
handle = []
|
||||
cm_entity = self.env['cm.entity'].sudo()
|
||||
for e in entities:
|
||||
ie = self.sudo().create(e)
|
||||
if len(e.get('entities', [])):
|
||||
for ce in e.get('entities', []):
|
||||
O = ce.copy()
|
||||
O['inter_entity_id'] = ie.id
|
||||
cm_entity.create(O)
|
||||
T = {
|
||||
'name': ie.name,
|
||||
'inter_entity_code': e['uuid'].split('-')[0],
|
||||
'type': 'external',
|
||||
'is_inter_entity': True,
|
||||
'is_master_entity': True,
|
||||
'inter_entity_id': ie.id,
|
||||
}
|
||||
cm_entity.with_context(broadcasted=True).create(T)
|
||||
handle.append((4, ie.id))
|
||||
if handle:
|
||||
sync = self.env['cm.inter_entity.sync'].sudo()
|
||||
setting = sync.search([], limit=1)
|
||||
setting.write({
|
||||
'entities': handle,
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
_logger.error(e)
|
||||
return False
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def add_new(self, arch):
|
||||
sync = self.env['cm.inter_entity.sync'].sudo()
|
||||
setting = sync.search([], limit=1)
|
||||
entities = self.sudo().get_entities()
|
||||
entity = self.sudo().create(arch)
|
||||
T = {
|
||||
'name': arch['name'],
|
||||
'inter_entity_code': arch['uuid'].split('-')[0],
|
||||
'type': 'external',
|
||||
'is_inter_entity': True,
|
||||
'is_master_entity': True,
|
||||
'inter_entity_id': entity.id,
|
||||
}
|
||||
self.env['cm.entity'].sudo().with_context(broadcasted=True).create(T)
|
||||
setting.write({
|
||||
'entities': [(4, entity.id)],
|
||||
})
|
||||
return entities
|
||||
|
||||
@api.model
|
||||
def wrap_jsonrpc(self, data):
|
||||
return {
|
||||
'jsonrpc': '2.0',
|
||||
'method': 'call',
|
||||
'id': None,
|
||||
'params': data,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def post(self, url, data):
|
||||
result = requests.post(url, json=data)
|
||||
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def is_success(self, result):
|
||||
r = result.json() or {}
|
||||
return 'success' in r.get('result', {})
|
||||
|
||||
@api.model
|
||||
def get_settings(self):
|
||||
sync = self.env['cm.inter_entity.sync'].sudo()
|
||||
setting = sync.search([], limit=1)
|
||||
return setting
|
||||
|
||||
@api.model
|
||||
def sync_new_key(self, key):
|
||||
sync = self.env['cm.inter_entity.sync'].sudo()
|
||||
setting = sync.search([], limit=1)
|
||||
SUBURL = u'/cm/sync/new_key'
|
||||
|
||||
for e in setting.entities.filtered(lambda k: k.uuid != setting.sync_key):
|
||||
data = self.wrap_jsonrpc({
|
||||
'key': key,
|
||||
'old': setting.sync_key,
|
||||
'auth': e.uuid,
|
||||
})
|
||||
url = u'{}{}'.format(e.url, SUBURL)
|
||||
result = self.post(url, data)
|
||||
if not self.is_success(result):
|
||||
raise Warning(_('Sync Error'u'Cannot Syncronize new key to Server {}, URL "{}"').format(e.name, e.url))
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def update_from(self, server):
|
||||
setting = self.sudo().get_settings()
|
||||
SUBURL = u'/cm/sync/update_from'
|
||||
|
||||
data = self.wrap_jsonrpc({
|
||||
'auth': server.uuid,
|
||||
'key': setting.sync_key,
|
||||
})
|
||||
url = u'{}{}'.format(server.url, SUBURL)
|
||||
result = self.post(url, data)
|
||||
if not self.is_success(result):
|
||||
raise Warning(_('Sync Error Cannot Syncronize new key to Server {}, URL "{}"').format(server.name, server.url))
|
||||
try:
|
||||
r = result.json()
|
||||
entities = r.get('result', {}).get('entities', [])
|
||||
handle = []
|
||||
cm_entity = self.env['cm.entity'].sudo()
|
||||
for e in entities:
|
||||
exists = setting.entities.filtered(lambda k: k.uuid == e['uuid'])
|
||||
if len(exists):
|
||||
exists.write(e)
|
||||
continue
|
||||
ie = self.sudo().create(e)
|
||||
if len(e.get('entities', [])):
|
||||
for ce in e.get('entities', []):
|
||||
O = ce.copy()
|
||||
O['inter_entity_id'] = ie.id
|
||||
cm_entity.create(O)
|
||||
try:
|
||||
T = {
|
||||
'name': ie.name,
|
||||
'inter_entity_code': e['uuid'].split('-')[0],
|
||||
'type': 'external',
|
||||
'is_inter_entity': True,
|
||||
'is_master_entity': True,
|
||||
'inter_entity_id': ie.id,
|
||||
}
|
||||
cm_entity.with_context(broadcasted=True).create(T)
|
||||
except Exception as e:
|
||||
_logger.error(e)
|
||||
handle.append((4, ie.id))
|
||||
if handle:
|
||||
sync = self.env['cm.inter_entity.sync'].sudo()
|
||||
setting = sync.search([], limit=1)
|
||||
setting.write({
|
||||
'entities': handle,
|
||||
})
|
||||
except Exception as ee:
|
||||
_logger.error(ee)
|
||||
return False
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def send_transaction(self, trasaction, instance, to_send):
|
||||
setting = self.sudo().get_settings()
|
||||
SUBURL = u'/cm/sync/send_transaction'
|
||||
for e in to_send:
|
||||
# trasaction['to_ids'] = e.inter_entity_code
|
||||
from_id = False
|
||||
K = instance.employee_id
|
||||
K = K.parent_id
|
||||
if K.is_inter_entity:
|
||||
from_id = K
|
||||
# while True:
|
||||
# if not len(K.parent_id):
|
||||
# break
|
||||
# K = K.parent_id
|
||||
# if K.is_inter_entity:
|
||||
# _logger.warning(
|
||||
# '----ccxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccc---------sendtransaction %s',
|
||||
# K.is_inter_entity)
|
||||
# from_id = K
|
||||
# break
|
||||
if from_id:
|
||||
trasaction['from_id'] = from_id.inter_entity_code
|
||||
else:
|
||||
trasaction['from_id'] = False
|
||||
data = self.wrap_jsonrpc({
|
||||
'data': trasaction,
|
||||
'key': setting.sync_key,
|
||||
'code': e.inter_entity_code,
|
||||
'auth': e.sudo().inter_entity_id.uuid,
|
||||
})
|
||||
url = u'{}{}'.format(e.sudo().inter_entity_id.url, SUBURL)
|
||||
result = self.post(url, data)
|
||||
# 'http://localhost:8069/cm/sync/send_transaction'
|
||||
if not self.is_success(result):
|
||||
_logger.error(result.json())
|
||||
raise Warning(_('Sync Error Cannot send Transaction to server {}').format(e.name))
|
||||
|
||||
@api.model
|
||||
def sync(self, entities):
|
||||
raise NotImplementedError('Not NotImplemented !')
|
||||
|
||||
@api.model
|
||||
def activate(self, arch):
|
||||
raise NotImplementedError('Not NotImplemented !')
|
||||
|
||||
@api.model
|
||||
def push_new(self, vals):
|
||||
"""here we have bug"""
|
||||
setting = self.sudo().get_settings()
|
||||
SUBURL = u'/cm/sync/push_new'
|
||||
for e in setting.entities.filtered(lambda k:
|
||||
k.uuid != setting.sync_key):
|
||||
data = self.wrap_jsonrpc({
|
||||
'data': vals,
|
||||
'auth': e.uuid,
|
||||
})
|
||||
url = u'{}{}'.format(e.url, SUBURL)
|
||||
result = self.post(url, data)
|
||||
if not self.is_success(result):
|
||||
raise Warning(_('Sync Error Cannot Syncronize new key to Server {}, URL "{}"').format(e.name, e.url))
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def clone(self, entity):
|
||||
raise NotImplementedError('Not NotImplemented !')
|
||||
|
||||
@api.model
|
||||
def update(self, vals):
|
||||
setting = self.sudo().get_settings()
|
||||
if vals['key'] != setting.sync_key:
|
||||
if not vals.get('broadcasted', False) and not vals.get('dont_appear_in_send', False):
|
||||
e = AccessError(_('Access Error'))
|
||||
e.args = (
|
||||
_('Access Error'), _('You cannot change syncronized entity data !'))
|
||||
raise e
|
||||
else:
|
||||
return True
|
||||
SUBURL = u'/cm/sync/update_entity'
|
||||
for e in setting.entities.filtered(lambda k:
|
||||
k.uuid != setting.sync_key):
|
||||
data = self.wrap_jsonrpc({
|
||||
'data': vals,
|
||||
'auth': e.uuid,
|
||||
})
|
||||
url = u'{}{}'.format(e.url, SUBURL)
|
||||
result = self.post(url, data)
|
||||
if not self.is_success(result):
|
||||
raise Warning(_('Sync Error Cannot Syncronize new key to Server {}, URL "{}"').format(e.name, e.url))
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def remove(self, vals):
|
||||
raise NotImplementedError('Not NotImplemented !')
|
||||
|
||||
@api.model
|
||||
def get_cm_entities(self, e):
|
||||
entity = self.env['cm.entity'].sudo()
|
||||
entities = entity.search(
|
||||
[('is_inter_entity', '=', True), ('inter_entity_id', '=', e.id)])
|
||||
result = []
|
||||
for ce in entities:
|
||||
result.append({
|
||||
'inter_entity_code': ce.inter_entity_code,
|
||||
'name': ce.name,
|
||||
'code': ce.code,
|
||||
'type': 'external',
|
||||
'is_inter_entity': True,
|
||||
})
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def get_entities(self):
|
||||
sync = self.env['cm.inter_entity.sync'].sudo()
|
||||
setting = sync.search([], limit=1)
|
||||
data = []
|
||||
for e in setting.entities:
|
||||
if e.id == setting.server_id.id:
|
||||
cm_entities = self.sudo().get_cm_entities(e)
|
||||
data.append({
|
||||
'name': e.name,
|
||||
'code': e.code,
|
||||
'uuid': e.uuid,
|
||||
'url': e.url,
|
||||
'entities': cm_entities,
|
||||
})
|
||||
return data
|
||||
|
||||
@api.model
|
||||
def authenticate(self, key):
|
||||
# add by Fatima 7/5/2020 for clean older code
|
||||
"""to check key of entity before sync using in controller method receive key and return true if right key"""
|
||||
sync = self.env['cm.inter_entity.sync'].sudo()
|
||||
setting = sync.search([], limit=1)
|
||||
try:
|
||||
if setting.sync_key == key.strip():
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
class Entity(models.Model):
|
||||
_inherit = 'cm.entity'
|
||||
|
||||
inter_entity_id = fields.Many2one('cm.inter_entity', string='Inter-Entities Ref')
|
||||
inter_entity_code = fields.Char(
|
||||
string='Inter-Entities Code')
|
||||
is_inter_entity = fields.Boolean(string='Is Inter-Entity ?', help='''
|
||||
If checked, this entity will be syncronized by other entities in the group.
|
||||
''')
|
||||
is_master_entity = fields.Boolean(string='Is Master-Entity ?', help='''
|
||||
If checked, this entity will be syncronized by other entities in the group.
|
||||
''')
|
||||
|
||||
@api.model
|
||||
def name_search(self, name='', args=None, operator='ilike', limit=100):
|
||||
args = args or []
|
||||
if not (name == '' and operator == 'ilike'):
|
||||
search = self.env['cm.inter_entity'].sudo().search([('name', 'ilike', name)])
|
||||
if len(search):
|
||||
args += ['|', ('inter_entity_id', 'in', search.ids)]
|
||||
return super(Entity, self).name_search(name=name, args=args, operator=operator, limit=limit)
|
||||
|
||||
def name_get(self):
|
||||
result = []
|
||||
for r in self:
|
||||
if r.is_inter_entity:
|
||||
if r.type == 'external':
|
||||
result.append((r.id, u'{} \u21E6 {}'.format(
|
||||
r.inter_entity_id.name or u'**', r.name)))
|
||||
continue
|
||||
result.append((r.id, r.name))
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
setting = self.env['cm.inter_entity'].sudo().get_settings()
|
||||
if vals.get('type', False) == 'unit' and vals.get('is_inter_entity', False):
|
||||
if not vals.get('inter_entity_code', False):
|
||||
vals['inter_entity_id'] = setting.server_id.id
|
||||
vals['inter_entity_code'] = u'{}-{}'.format(setting.sync_key.split('-')[0] if setting.sync_key else False,
|
||||
self.env['ir.sequence'].sudo().next_by_code('cm.inter.entity'))
|
||||
obj = super(Entity, self).create(vals)
|
||||
IE = self.env['cm.inter_entity'].sudo()
|
||||
if vals.get('type', False) == 'unit' and vals.get('is_inter_entity', False):
|
||||
if not self.env.context.get('broadcasted', False):
|
||||
IE.push_new({
|
||||
'data': vals,
|
||||
'key': setting.sync_key,
|
||||
})
|
||||
return obj
|
||||
|
||||
# def unlink(self, cr, uid, ids, context=None):
|
||||
# return super(Entity, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
def write(self, vals):
|
||||
data = {}
|
||||
values = vals.copy()
|
||||
is_inter_entity = False
|
||||
setting = self.env['cm.inter_entity'].sudo().get_settings()
|
||||
if vals.get('is_inter_entity', False):
|
||||
values['inter_entity_id'] = setting.server_id.id
|
||||
values['inter_entity_code'] = u'{}-{}'.format(setting.sync_key.split(
|
||||
'-')[0], self.env['ir.sequence'].sudo().next_by_code('cm.inter.entity'))
|
||||
vals['inter_entity_id'] = values['inter_entity_id']
|
||||
vals['inter_entity_code'] = values['inter_entity_code']
|
||||
is_inter_entity = True
|
||||
for r in self:
|
||||
if r.is_inter_entity:
|
||||
data = {
|
||||
'details': {'code': r.inter_entity_code, 'data': vals},
|
||||
'key': r.inter_entity_id.uuid,
|
||||
'broadcasted': vals.get('broadcasted', False)
|
||||
}
|
||||
if not is_inter_entity:
|
||||
data['details']['remove'] = True
|
||||
elif is_inter_entity:
|
||||
vals1 = r.read([])
|
||||
vals1 = vals1[0]
|
||||
lister = [
|
||||
'name', 'inter_entity_code',
|
||||
'is_inter_entity',
|
||||
]
|
||||
vals2, vals3 = {}, {}
|
||||
for l in lister:
|
||||
if l in vals1:
|
||||
vals2[l] = vals1[l]
|
||||
if l in vals:
|
||||
vals3[l] = vals[l]
|
||||
vals2.update(vals3)
|
||||
if vals2:
|
||||
code = vals2.get('inter_entity_code', r.inter_entity_code)
|
||||
data = {
|
||||
'details': {'code': code, 'data': vals2, 'is_new': True},
|
||||
'key': setting.sync_key,
|
||||
'broadcasted': vals.get('broadcasted', False)
|
||||
}
|
||||
u = super(Entity, self).write(values)
|
||||
if data:
|
||||
IE = self.env['cm.inter_entity'].sudo()
|
||||
IE.update(data)
|
||||
return u
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
import base64
|
||||
from odoo import api, models, fields, _, exceptions
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Transaction(models.Model):
|
||||
_inherit = 'outgoing.transaction'
|
||||
|
||||
syncronized = fields.Boolean(string='Syncronized ?')
|
||||
|
||||
|
||||
def action_draft(self):
|
||||
super(Transaction, self).action_draft()
|
||||
to_send = []
|
||||
inter_entity = self.env['cm.inter_entity'].sudo()
|
||||
for r in self:
|
||||
r.write({
|
||||
'syncronized': True,
|
||||
})
|
||||
for e in r.to_ids:
|
||||
if e.is_inter_entity:
|
||||
to_send.append(e)
|
||||
attachment_rule_data = []
|
||||
for attachment in r.attachment_rule_ids:
|
||||
attachment_rule_data.append({
|
||||
'id': attachment.id if attachment else '',
|
||||
'file_save': attachment.file_save.decode('utf-8') if attachment.file_save else '',
|
||||
'attachment_filename': u"".join(u'%s'%attachment.attachment_filename) if attachment.attachment_filename else '',
|
||||
'outgoing_id': False,
|
||||
'incoming_transaction_id': r.id if r else False,
|
||||
'internal_id': False,
|
||||
'date': attachment.date if attachment.date else '',
|
||||
'description': attachment.description if attachment.description else '',
|
||||
})
|
||||
if len(to_send):
|
||||
trasaction = {
|
||||
# 'out_date': r.out_date,
|
||||
'to_ids': None,
|
||||
'type': 'new',
|
||||
'subject': r.subject,
|
||||
'incoming_number': r.name,
|
||||
'incoming_date': r.transaction_date,
|
||||
'syncronized': True,
|
||||
'body': r.body,
|
||||
'attachment_rule_ids': attachment_rule_data,
|
||||
}
|
||||
inter_entity.send_transaction(trasaction, r, to_send)
|
||||
|
||||
|
||||
class Incoming(models.Model):
|
||||
_inherit = 'incoming.transaction'
|
||||
|
||||
syncronized = fields.Boolean(string='Syncronized ?')
|
||||
inter_entity_id = fields.Many2one('cm.inter_entity', string='Inter Entity')
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
'''Doc'''
|
||||
import logging
|
||||
from odoo import api, models, fields, _
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Sync(models.Model):
|
||||
'''Doc'''
|
||||
_name = 'cm.inter_entity.sync'
|
||||
_description = 'Entity Syncronization'
|
||||
|
||||
activated = fields.Boolean(string='Activate Syncronization')
|
||||
sync_key = fields.Char(string='Sync Key', related='server_id.uuid')
|
||||
server_id = fields.Many2one('cm.inter_entity', string='Current Server', store=True)
|
||||
entities = fields.Many2many(
|
||||
'cm.inter_entity', 'inter_entity_sync_rel', 'sync_id', 'inter_entity_id')
|
||||
|
||||
important_id = fields.Many2one(
|
||||
'cm.transaction.important', string='Default Important Degree')
|
||||
subject_type_id = fields.Many2one(
|
||||
'cm.subject.type', string='Default Transaction Type')
|
||||
employee_id = fields.Many2one(
|
||||
'cm.entity', string='Default Created By')
|
||||
|
||||
def generate_key(self):
|
||||
'''Doc'''
|
||||
inter_entity = self.env['cm.inter_entity'].sudo()
|
||||
for rec in self:
|
||||
# if not len(rec.entities.filtered(lambda k: k.uuid != rec.sync_key)):
|
||||
# first time
|
||||
return {
|
||||
'name': _('Generate new Key'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_id': False,
|
||||
'res_model': 'cm.inter.entity.wizard',
|
||||
'target': 'new',
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': {
|
||||
'default_document_id': rec.id,
|
||||
'default_broadcast': True,
|
||||
},
|
||||
}
|
||||
# k = inter_entity.generate_key()
|
||||
# synced = inter_entity.sync_new_key(k)
|
||||
# print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>synced",synced)
|
||||
# if synced:
|
||||
# rec.write({
|
||||
# 'sync_key': k,
|
||||
# })
|
||||
|
||||
def update_from(self):
|
||||
'''Doc'''
|
||||
inter_entity = self.env['cm.inter_entity'].sudo()
|
||||
for rec in self:
|
||||
if len(rec.entities.filtered(lambda k: k.uuid != rec.sync_key)):
|
||||
# first time
|
||||
return {
|
||||
'name': _('Update From ...'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_id': False,
|
||||
'res_model': 'cm.inter.entity.update.wizard',
|
||||
'target': 'new',
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': {
|
||||
'default_document_id': rec.id,
|
||||
'default_broadcast': True,
|
||||
},
|
||||
}
|
||||
k = inter_entity.generate_key()
|
||||
synced = inter_entity.sync_new_key(k)
|
||||
if synced:
|
||||
rec.write({
|
||||
'sync_key': k,
|
||||
})
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_inter_objects_manager,access_outgoing_inter_objects_manager,model_cm_inter_entity,exp_transaction_documents.group_cm_employee_group,1,1,1,1
|
||||
access_inter_objects_reviewer,access_outgoing_inter_objects_reviewer_manager,model_cm_inter_entity,exp_transaction_documents.group_cm_user,1,1,1,1
|
||||
access_inter_objects_unit_manager,access_outgoing_inter_objects_unit_manager,model_cm_inter_entity,exp_transaction_documents.group_cm_reviewer,1,1,1,1
|
||||
access_inter_objects_dep,access_outgoing_inter_objects_dep,model_cm_inter_entity,exp_transaction_documents.group_cm_department_manager,1,1,1,1
|
||||
access_outgoing_inter_objects_exe,access_outgoing_inter_objects_exe,model_cm_inter_entity,exp_transaction_documents.group_cm_executive_manager,1,1,1,1
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record model="ir.actions.act_window" id="cm_inter_entity_sync_action">
|
||||
<field name="name">Inter Entity Sync</field>
|
||||
<field name="res_model">cm.inter_entity.sync</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="res_id" ref="cm_entity_sync_odex.sync_settings"/>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem id="cm_inter_entity_sync_menu" name="Inter Entity Sync"
|
||||
parent="exp_transaction_documents.cm_settings_menu" action="cm_inter_entity_sync_action" groups="base.group_no_one" />
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="cm_inter_entity_tree" model="ir.ui.view">
|
||||
<field name="name">cm.inter_entity.tree</field>
|
||||
<field name="model">cm.inter_entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Inter-Entities">
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="url"/>
|
||||
<field name="uuid"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="cm_inter_entity_form" model="ir.ui.view">
|
||||
<field name="name">cm.inter_entity.form</field>
|
||||
<field name="model">cm.inter_entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Inter-Entity">
|
||||
<group>
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="url"/>
|
||||
<field name="uuid"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="cm_entity_form" model="ir.ui.view">
|
||||
<field name="name">cm.entity.form</field>
|
||||
<field name="model">cm.entity</field>
|
||||
<field name="inherit_id" ref="exp_transaction_documents.cm_entity_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="manager_id" position="after">
|
||||
<field name="is_inter_entity" attrs="{'invisible':[('type','not in',['unit','external'])], 'readonly':[('type', '=','external')]}"/>
|
||||
<field name="inter_entity_id" widget="selection" attrs="{'invisible':[('type','not in',['unit','external'])], 'readonly':True}"/>
|
||||
<field name="inter_entity_code" attrs="{'invisible':[('type','not in',['unit','external'])], 'readonly':True}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<!-- <record id="cm_entity_search" model="ir.ui.view">-->
|
||||
<!-- <field name="name">cm.entity.filter.ext</field>-->
|
||||
<!-- <field name="model">cm.entity</field>-->
|
||||
<!-- <field name="inherit_id" ref="cm_odex.cm_entity_search" />-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <field name="name" position="attributes">-->
|
||||
<!-- <attribute name="string">Entity</attribute>-->
|
||||
<!-- <attribute name="filter_domain">['|','|','|','|','|','|','|',('name','ilike',self),('job_title_id.name', 'ilike', self),('parent_id.name', 'ilike', self),('manager_id.name', 'ilike', self),('partner_id.email', 'ilike', self),('partner_id.name', 'ilike', self),('code', 'ilike', self),('inter_entity_id.name', 'ilike', self)]</attribute>-->
|
||||
<!-- </field>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record id="view_cm_sync_config" model="ir.ui.view">
|
||||
<field name="name">CM Settings Ext</field>
|
||||
<field name="model">cm.inter_entity.sync</field>
|
||||
<field name="arch" type="xml">
|
||||
<form create="false" delete="false">
|
||||
<group>
|
||||
<group string="Activate Syncronization">
|
||||
<field name="activated"/>
|
||||
<field name="sync_key" attrs="{'readonly':True,'invisible':[('activated','=',False)]}"/>
|
||||
<field name="server_id" attrs="{'readonly':True,'invisible':[('activated','=',False)]}"/>
|
||||
<button string="Generate Key" type="object" name="generate_key" attrs="{'invisible':[('activated','=',False)]}" class="oe_highlight"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="important_id" attrs="{'required':True}" widget="selection"/>
|
||||
<field name="subject_type_id" attrs="{'required':True}" widget="selection"/>
|
||||
<field name="employee_id" attrs="{'required':True}" domain="[('type','=','employee')]"/>
|
||||
<button string="Update From ..." type="object" name="update_from" attrs="{'invisible':[('activated','=',False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="Inter Entities">
|
||||
|
||||
</separator>
|
||||
<field name="entities" readonly="True">
|
||||
<tree editable="bottom">
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="url"/>
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from . import wizards
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<openerp>
|
||||
<data>
|
||||
<record id="view_cm_inter_entity_wizard" model="ir.ui.view">
|
||||
<field name="name">CM - Inter entity Wizard</field>
|
||||
<field name="model">cm.inter.entity.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="">
|
||||
<group>
|
||||
<group>
|
||||
<field name="broadcast"/>
|
||||
|
||||
<field name="server_url" attrs="{'required': [('broadcast','=',True)],'invisible':[('broadcast','=',False)]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="document_id" invisible="True" readonly="True"/>
|
||||
<field name="key" invisible="True"/>
|
||||
<field name="server_key" attrs="{'required': [('broadcast','=',True)],'invisible':[('broadcast','=',False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Generate" type="object" name="generate" class="oe_highlight"/>
|
||||
or
|
||||
<button special="cancel" string="Cancel" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_cm_inter_entity_update_wizard" model="ir.ui.view">
|
||||
<field name="name">CM - Inter entity Update Wizard</field>
|
||||
<field name="model">cm.inter.entity.update.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="">
|
||||
<group>
|
||||
<group>
|
||||
<field name="server_id" domain="[('id','!=',primary_id)]" widget="selection" required="True"/>
|
||||
|
||||
</group>
|
||||
<group>
|
||||
<field name="primary_id" invisible="True" readonly="True"/>
|
||||
<field name="document_id" invisible="True" readonly="True"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Update" type="object" name="update" class="oe_highlight"/>
|
||||
or
|
||||
<button special="cancel" string="Cancel" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import api, models, fields, _, exceptions
|
||||
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AddNew(models.TransientModel):
|
||||
_name = 'cm.inter.entity.wizard'
|
||||
|
||||
document_id = fields.Many2one('cm.inter_entity.sync', string='Document')
|
||||
broadcast = fields.Boolean(string='Broadcast')
|
||||
key = fields.Char(string='Sync Key')
|
||||
server_url = fields.Char('Server URL')
|
||||
server_key = fields.Char(string='Server Key')
|
||||
|
||||
def generate(self):
|
||||
inter_entity = self.env['cm.inter_entity'].sudo()
|
||||
for rec in self:
|
||||
K = inter_entity.generate_key()
|
||||
rec.key = K
|
||||
company_code = K.split('-')[0]
|
||||
company_name = self.env.user.company_id.name
|
||||
company_url = self.env['ir.config_parameter'].sudo(
|
||||
).get_param('web.base.url')
|
||||
# company_url = company_url.replace('http://', 'https://')
|
||||
synced = inter_entity.sync_new_key(K)
|
||||
if synced:
|
||||
rec.document_id.write({
|
||||
'sync_key': K,
|
||||
})
|
||||
if rec.broadcast:
|
||||
url = rec.server_url
|
||||
key = rec.server_key
|
||||
added = inter_entity.broadcast(url=url, key=key, new_key=K)
|
||||
if not added:
|
||||
raise exceptions.Warning(_('Broadcast Error !'
|
||||
u'Error While Broadcast new Server, please check server key and url.'))
|
||||
data = {
|
||||
'name': company_name,
|
||||
'code': company_code,
|
||||
'url': company_url,
|
||||
'uuid': K,
|
||||
}
|
||||
if len(rec.document_id.server_id):
|
||||
rec.document_id.server_id.write({
|
||||
'uuid': K,
|
||||
'code': company_code,
|
||||
'name': company_name,
|
||||
'url': company_url,
|
||||
})
|
||||
else:
|
||||
entity = inter_entity.create(data)
|
||||
rec.document_id.write({
|
||||
'server_id': entity.id,
|
||||
'entities': [(4, entity.id)]
|
||||
})
|
||||
|
||||
|
||||
class Update(models.TransientModel):
|
||||
_name = 'cm.inter.entity.update.wizard'
|
||||
|
||||
document_id = fields.Many2one('cm.inter_entity.sync', string='Document')
|
||||
primary_id = fields.Many2one('cm.inter_entity', string='Main Server', related='document_id.server_id', store=True)
|
||||
server_id = fields.Many2one('cm.inter_entity', string='Update Server')
|
||||
|
||||
def update(self):
|
||||
for r in self:
|
||||
|
||||
setting = r.document_id
|
||||
r.primary_id.sudo().update_from(r.server_id)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odex - Communications Management System.
|
||||
# Copyright (C) 2018 Expert Co. Ltd. (<http://exp-sa.com>).
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'Communications Management Barcodes Reports',
|
||||
'version': '0.1',
|
||||
'sequence': 4,
|
||||
'author': 'Expert Co. Ltd.',
|
||||
'category': 'Odex25-Transactions/Odex25-Transactions',
|
||||
'summary': 'Correspondence Management System',
|
||||
'description': """
|
||||
Odex - Communications Management Reports
|
||||
========================================
|
||||
""",
|
||||
'website': 'http://www.exp-sa.com',
|
||||
'depends': ['exp_transaction_documents'],
|
||||
'data': [
|
||||
'reports/barcodes.xml',
|
||||
'reports/extend_transaction_detail_report.xml',
|
||||
'views/transactions_views.xml',
|
||||
'views/assets.xml',
|
||||
],
|
||||
'qweb': [
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': False,
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * cm_odex_barcode
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 11.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-07-13 09:32+0000\n"
|
||||
"PO-Revision-Date: 2020-07-13 09:32+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.extend_tran_header
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.report_transaction_barcode
|
||||
msgid "<span style=\"font-weight:bold\">Attachment:</span>"
|
||||
msgstr "<span style=\"font-weight:bold\">المرفقات:</span>"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.report_transaction_barcode
|
||||
msgid "<span style=\"font-weight:bold\">Date:</span>"
|
||||
msgstr "<span style=\"font-weight:bold\">التاريخ:</span>"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.report_transaction_barcode
|
||||
msgid "<span style=\"font-weight:bold\">Reference:</span>"
|
||||
msgstr "<span style=\"font-weight:bold\">المرجع:</span>"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.extend_tran_header
|
||||
msgid "<span style=\"font-weight:bold;\">Reference:</span>"
|
||||
msgstr "<span style=\"font-weight:bold;\">المرجع:</span>"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.extend_tran_header
|
||||
msgid "<span style=\"font-weight:bold;font-stretch: expanded;\">\n"
|
||||
" Date:</span>"
|
||||
msgstr "<span style=\"font-weight:bold;font-stretch: expanded;\">\n"
|
||||
" التاريخ:</span>"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.model.fields,field_description:cm_odex_barcode.field_incoming_transaction_binary_barcode
|
||||
#: model:ir.model.fields,field_description:cm_odex_barcode.field_internal_transaction_binary_barcode
|
||||
#: model:ir.model.fields,field_description:cm_odex_barcode.field_outgoing_transaction_binary_barcode
|
||||
#: model:ir.model.fields,field_description:cm_odex_barcode.field_transaction_transaction_binary_barcode
|
||||
msgid "Barcode"
|
||||
msgstr "باركود"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#. openerp-web
|
||||
#: code:addons/cm_odex_barcode/static/src/js/cm_odex_barcode.js:47
|
||||
#, python-format
|
||||
msgid "Could not display the selected image."
|
||||
msgstr "Could not display the selected image."
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#. openerp-web
|
||||
#: code:addons/cm_odex_barcode/static/src/js/cm_odex_barcode.js:47
|
||||
#, python-format
|
||||
msgid "Image"
|
||||
msgstr "Image"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.actions.report,name:cm_odex_barcode.act_transaction_in_barcode
|
||||
msgid "Incoming Transaction Barcode"
|
||||
msgstr "باركود المعاملات الورادة"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.actions.report,name:cm_odex_barcode.act_transaction_internal_barcode
|
||||
msgid "Internal Transaction Barcode"
|
||||
msgstr "باركود المعاملات الداخلية"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.extend_tran_header
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.report_transaction_barcode
|
||||
msgid "Number:"
|
||||
msgstr "رقم المعاملة:"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.actions.report,name:cm_odex_barcode.act_transaction_out_barcode
|
||||
msgid "Outgoing Transaction Barcode"
|
||||
msgstr "باركود المعاملات الصادره"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.form_incoming_barcode_print_button
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.form_internal_barcode_print_button
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.form_outgoing_barcode_print_button
|
||||
msgid "Print Barcode"
|
||||
msgstr "طباعة الباركود"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.form_incoming_barcode_print_button
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.form_internal_barcode_print_button
|
||||
#: model:ir.ui.view,arch_db:cm_odex_barcode.form_outgoing_barcode_print_button
|
||||
msgid "Review Barcode"
|
||||
msgstr "مراجعة الباركود"
|
||||
|
||||
#. module: cm_odex_barcode
|
||||
#: model:ir.model,name:cm_odex_barcode.model_transaction_transaction
|
||||
msgid "for common attribute between transaction"
|
||||
msgstr "for common attribute between transaction"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
from . import barcode
|
||||
from . import arabic_reshaper
|
||||
|
|
@ -0,0 +1,359 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This work is licensed under the GNU Public License (GPL).
|
||||
# To view a copy of this license, visit http://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
# Written by Abdullah Diab (mpcabd)
|
||||
# Email: mpcabd@gmail.com
|
||||
# Website: http://mpcabd.xyz
|
||||
|
||||
# Ported and tweaked from Java to Python, from Better Arabic Reshaper
|
||||
# [https://github.com/agawish/Better-Arabic-Reshaper/]
|
||||
|
||||
# Usage:
|
||||
# Install python-bidi [https://github.com/MeirKriheli/python-bidi], can be
|
||||
# installed from pip `pip install python-bidi`.
|
||||
|
||||
# import arabic_reshaper
|
||||
# from bidi.algorithm import get_display
|
||||
# reshaped_text = arabic_reshaper.reshape(u'اللغة العربية رائعة')
|
||||
# bidi_text = get_display(reshaped_text)
|
||||
# Now you can pass `bidi_text` to any function that handles
|
||||
# displaying/printing of the text, like writing it to PIL Image or passing
|
||||
# it to a PDF generating method.
|
||||
|
||||
import re
|
||||
|
||||
DEFINED_CHARACTERS_ORGINAL_ALF_UPPER_MDD = u'\u0622'
|
||||
DEFINED_CHARACTERS_ORGINAL_ALF_UPPER_HAMAZA = u'\u0623'
|
||||
DEFINED_CHARACTERS_ORGINAL_ALF_LOWER_HAMAZA = u'\u0625'
|
||||
DEFINED_CHARACTERS_ORGINAL_ALF = u'\u0627'
|
||||
DEFINED_CHARACTERS_ORGINAL_LAM = u'\u0644'
|
||||
|
||||
LAM_ALEF_GLYPHS = [
|
||||
[u'\u0622', u'\uFEF6', u'\uFEF5'],
|
||||
[u'\u0623', u'\uFEF8', u'\uFEF7'],
|
||||
[u'\u0627', u'\uFEFC', u'\uFEFB'],
|
||||
[u'\u0625', u'\uFEFA', u'\uFEF9']
|
||||
]
|
||||
|
||||
HARAKAT = [
|
||||
u'\u0600', u'\u0601', u'\u0602', u'\u0603', u'\u0606', u'\u0607', u'\u0608', u'\u0609',
|
||||
u'\u060A', u'\u060B', u'\u060D', u'\u060E', u'\u0610', u'\u0611', u'\u0612', u'\u0613',
|
||||
u'\u0614', u'\u0615', u'\u0616', u'\u0617', u'\u0618', u'\u0619', u'\u061A', u'\u061B',
|
||||
u'\u061E', u'\u061F', u'\u0621', u'\u063B', u'\u063C', u'\u063D', u'\u063E', u'\u063F',
|
||||
u'\u0640', u'\u064B', u'\u064C', u'\u064D', u'\u064E', u'\u064F', u'\u0650', u'\u0651',
|
||||
u'\u0652', u'\u0653', u'\u0654', u'\u0655', u'\u0656', u'\u0657', u'\u0658', u'\u0659',
|
||||
u'\u065A', u'\u065B', u'\u065C', u'\u065D', u'\u065E', u'\u0660', u'\u066A', u'\u066B',
|
||||
u'\u066C', u'\u066F', u'\u0670', u'\u0672', u'\u06D4', u'\u06D5', u'\u06D6', u'\u06D7',
|
||||
u'\u06D8', u'\u06D9', u'\u06DA', u'\u06DB', u'\u06DC', u'\u06DF', u'\u06E0', u'\u06E1',
|
||||
u'\u06E2', u'\u06E3', u'\u06E4', u'\u06E5', u'\u06E6', u'\u06E7', u'\u06E8', u'\u06E9',
|
||||
u'\u06EA', u'\u06EB', u'\u06EC', u'\u06ED', u'\u06EE', u'\u06EF', u'\u06D6', u'\u06D7',
|
||||
u'\u06D8', u'\u06D9', u'\u06DA', u'\u06DB', u'\u06DC', u'\u06DD', u'\u06DE', u'\u06DF',
|
||||
u'\u06F0', u'\u06FD', u'\uFE70', u'\uFE71', u'\uFE72', u'\uFE73', u'\uFE74', u'\uFE75',
|
||||
u'\uFE76', u'\uFE77', u'\uFE78', u'\uFE79', u'\uFE7A', u'\uFE7B', u'\uFE7C', u'\uFE7D',
|
||||
u'\uFE7E', u'\uFE7F', u'\uFC5E', u'\uFC5F', u'\uFC60', u'\uFC61', u'\uFC62', u'\uFC63'
|
||||
]
|
||||
|
||||
ARABIC_GLYPHS = {
|
||||
u'\u0622': [u'\u0622', u'\uFE81', u'\uFE81', u'\uFE82', u'\uFE82', 2],
|
||||
u'\u0623': [u'\u0623', u'\uFE83', u'\uFE83', u'\uFE84', u'\uFE84', 2],
|
||||
u'\u0624': [u'\u0624', u'\uFE85', u'\uFE85', u'\uFE86', u'\uFE86', 2],
|
||||
u'\u0625': [u'\u0625', u'\uFE87', u'\uFE87', u'\uFE88', u'\uFE88', 2],
|
||||
u'\u0626': [u'\u0626', u'\uFE89', u'\uFE8B', u'\uFE8C', u'\uFE8A', 4],
|
||||
u'\u0627': [u'\u0627', u'\u0627', u'\u0627', u'\uFE8E', u'\uFE8E', 2],
|
||||
u'\u0628': [u'\u0628', u'\uFE8F', u'\uFE91', u'\uFE92', u'\uFE90', 4],
|
||||
u'\u0629': [u'\u0629', u'\uFE93', u'\uFE93', u'\uFE94', u'\uFE94', 2],
|
||||
u'\u062A': [u'\u062A', u'\uFE95', u'\uFE97', u'\uFE98', u'\uFE96', 4],
|
||||
u'\u062B': [u'\u062B', u'\uFE99', u'\uFE9B', u'\uFE9C', u'\uFE9A', 4],
|
||||
u'\u062C': [u'\u062C', u'\uFE9D', u'\uFE9F', u'\uFEA0', u'\uFE9E', 4],
|
||||
u'\u062D': [u'\u062D', u'\uFEA1', u'\uFEA3', u'\uFEA4', u'\uFEA2', 4],
|
||||
u'\u062E': [u'\u062E', u'\uFEA5', u'\uFEA7', u'\uFEA8', u'\uFEA6', 4],
|
||||
u'\u062F': [u'\u062F', u'\uFEA9', u'\uFEA9', u'\uFEAA', u'\uFEAA', 2],
|
||||
u'\u0630': [u'\u0630', u'\uFEAB', u'\uFEAB', u'\uFEAC', u'\uFEAC', 2],
|
||||
u'\u0631': [u'\u0631', u'\uFEAD', u'\uFEAD', u'\uFEAE', u'\uFEAE', 2],
|
||||
u'\u0632': [u'\u0632', u'\uFEAF', u'\uFEAF', u'\uFEB0', u'\uFEB0', 2],
|
||||
u'\u0633': [u'\u0633', u'\uFEB1', u'\uFEB3', u'\uFEB4', u'\uFEB2', 4],
|
||||
u'\u0634': [u'\u0634', u'\uFEB5', u'\uFEB7', u'\uFEB8', u'\uFEB6', 4],
|
||||
u'\u0635': [u'\u0635', u'\uFEB9', u'\uFEBB', u'\uFEBC', u'\uFEBA', 4],
|
||||
u'\u0636': [u'\u0636', u'\uFEBD', u'\uFEBF', u'\uFEC0', u'\uFEBE', 4],
|
||||
u'\u0637': [u'\u0637', u'\uFEC1', u'\uFEC3', u'\uFEC4', u'\uFEC2', 4],
|
||||
u'\u0638': [u'\u0638', u'\uFEC5', u'\uFEC7', u'\uFEC8', u'\uFEC6', 4],
|
||||
u'\u0639': [u'\u0639', u'\uFEC9', u'\uFECB', u'\uFECC', u'\uFECA', 4],
|
||||
u'\u063A': [u'\u063A', u'\uFECD', u'\uFECF', u'\uFED0', u'\uFECE', 4],
|
||||
u'\u0641': [u'\u0641', u'\uFED1', u'\uFED3', u'\uFED4', u'\uFED2', 4],
|
||||
u'\u0642': [u'\u0642', u'\uFED5', u'\uFED7', u'\uFED8', u'\uFED6', 4],
|
||||
u'\u0643': [u'\u0643', u'\uFED9', u'\uFEDB', u'\uFEDC', u'\uFEDA', 4],
|
||||
u'\u0644': [u'\u0644', u'\uFEDD', u'\uFEDF', u'\uFEE0', u'\uFEDE', 4],
|
||||
u'\u0645': [u'\u0645', u'\uFEE1', u'\uFEE3', u'\uFEE4', u'\uFEE2', 4],
|
||||
u'\u0646': [u'\u0646', u'\uFEE5', u'\uFEE7', u'\uFEE8', u'\uFEE6', 4],
|
||||
u'\u0647': [u'\u0647', u'\uFEE9', u'\uFEEB', u'\uFEEC', u'\uFEEA', 4],
|
||||
u'\u0648': [u'\u0648', u'\uFEED', u'\uFEED', u'\uFEEE', u'\uFEEE', 2],
|
||||
u'\u0649': [u'\u0649', u'\uFEEF', u'\uFEEF', u'\uFEF0', u'\uFEF0', 2],
|
||||
u'\u0671': [u'\u0671', u'\u0671', u'\u0671', u'\uFB51', u'\uFB51', 2],
|
||||
u'\u064A': [u'\u064A', u'\uFEF1', u'\uFEF3', u'\uFEF4', u'\uFEF2', 4],
|
||||
u'\u066E': [u'\u066E', u'\uFBE4', u'\uFBE8', u'\uFBE9', u'\uFBE5', 4],
|
||||
u'\u06AA': [u'\u06AA', u'\uFB8E', u'\uFB90', u'\uFB91', u'\uFB8F', 4],
|
||||
u'\u06C1': [u'\u06C1', u'\uFBA6', u'\uFBA8', u'\uFBA9', u'\uFBA7', 4],
|
||||
u'\u06E4': [u'\u06E4', u'\u06E4', u'\u06E4', u'\u06E4', u'\uFEEE', 2],
|
||||
u'\u067E': [u'\u067E', u'\uFB56', u'\uFB58', u'\uFB59', u'\uFB57', 4],
|
||||
u'\u0698': [u'\u0698', u'\uFB8A', u'\uFB8A', u'\uFB8A', u'\uFB8B', 2],
|
||||
u'\u06AF': [u'\u06AF', u'\uFB92', u'\uFB94', u'\uFB95', u'\uFB93', 4],
|
||||
u'\u0686': [u'\u0686', u'\uFB7A', u'\uFB7C', u'\uFB7D', u'\uFB7B', 4],
|
||||
u'\u06A9': [u'\u06A9', u'\uFB8E', u'\uFB90', u'\uFB91', u'\uFB8F', 4],
|
||||
u'\u06CC': [u'\u06CC', u'\uFEEF', u'\uFEF3', u'\uFEF4', u'\uFEF0', 4]
|
||||
}
|
||||
|
||||
ARABIC_GLYPHS_LIST = [
|
||||
[u'\u0622', u'\uFE81', u'\uFE81', u'\uFE82', u'\uFE82', 2],
|
||||
[u'\u0623', u'\uFE83', u'\uFE83', u'\uFE84', u'\uFE84', 2],
|
||||
[u'\u0624', u'\uFE85', u'\uFE85', u'\uFE86', u'\uFE86', 2],
|
||||
[u'\u0625', u'\uFE87', u'\uFE87', u'\uFE88', u'\uFE88', 2],
|
||||
[u'\u0626', u'\uFE89', u'\uFE8B', u'\uFE8C', u'\uFE8A', 4],
|
||||
[u'\u0627', u'\u0627', u'\u0627', u'\uFE8E', u'\uFE8E', 2],
|
||||
[u'\u0628', u'\uFE8F', u'\uFE91', u'\uFE92', u'\uFE90', 4],
|
||||
[u'\u0629', u'\uFE93', u'\uFE93', u'\uFE94', u'\uFE94', 2],
|
||||
[u'\u062A', u'\uFE95', u'\uFE97', u'\uFE98', u'\uFE96', 4],
|
||||
[u'\u062B', u'\uFE99', u'\uFE9B', u'\uFE9C', u'\uFE9A', 4],
|
||||
[u'\u062C', u'\uFE9D', u'\uFE9F', u'\uFEA0', u'\uFE9E', 4],
|
||||
[u'\u062D', u'\uFEA1', u'\uFEA3', u'\uFEA4', u'\uFEA2', 4],
|
||||
[u'\u062E', u'\uFEA5', u'\uFEA7', u'\uFEA8', u'\uFEA6', 4],
|
||||
[u'\u062F', u'\uFEA9', u'\uFEA9', u'\uFEAA', u'\uFEAA', 2],
|
||||
[u'\u0630', u'\uFEAB', u'\uFEAB', u'\uFEAC', u'\uFEAC', 2],
|
||||
[u'\u0631', u'\uFEAD', u'\uFEAD', u'\uFEAE', u'\uFEAE', 2],
|
||||
[u'\u0632', u'\uFEAF', u'\uFEAF', u'\uFEB0', u'\uFEB0', 2],
|
||||
[u'\u0633', u'\uFEB1', u'\uFEB3', u'\uFEB4', u'\uFEB2', 4],
|
||||
[u'\u0634', u'\uFEB5', u'\uFEB7', u'\uFEB8', u'\uFEB6', 4],
|
||||
[u'\u0635', u'\uFEB9', u'\uFEBB', u'\uFEBC', u'\uFEBA', 4],
|
||||
[u'\u0636', u'\uFEBD', u'\uFEBF', u'\uFEC0', u'\uFEBE', 4],
|
||||
[u'\u0637', u'\uFEC1', u'\uFEC3', u'\uFEC4', u'\uFEC2', 4],
|
||||
[u'\u0638', u'\uFEC5', u'\uFEC7', u'\uFEC8', u'\uFEC6', 4],
|
||||
[u'\u0639', u'\uFEC9', u'\uFECB', u'\uFECC', u'\uFECA', 4],
|
||||
[u'\u063A', u'\uFECD', u'\uFECF', u'\uFED0', u'\uFECE', 4],
|
||||
[u'\u0641', u'\uFED1', u'\uFED3', u'\uFED4', u'\uFED2', 4],
|
||||
[u'\u0642', u'\uFED5', u'\uFED7', u'\uFED8', u'\uFED6', 4],
|
||||
[u'\u0643', u'\uFED9', u'\uFEDB', u'\uFEDC', u'\uFEDA', 4],
|
||||
[u'\u0644', u'\uFEDD', u'\uFEDF', u'\uFEE0', u'\uFEDE', 4],
|
||||
[u'\u0645', u'\uFEE1', u'\uFEE3', u'\uFEE4', u'\uFEE2', 4],
|
||||
[u'\u0646', u'\uFEE5', u'\uFEE7', u'\uFEE8', u'\uFEE6', 4],
|
||||
[u'\u0647', u'\uFEE9', u'\uFEEB', u'\uFEEC', u'\uFEEA', 4],
|
||||
[u'\u0648', u'\uFEED', u'\uFEED', u'\uFEEE', u'\uFEEE', 2],
|
||||
[u'\u0649', u'\uFEEF', u'\uFEEF', u'\uFEF0', u'\uFEF0', 2],
|
||||
[u'\u0671', u'\u0671', u'\u0671', u'\uFB51', u'\uFB51', 2],
|
||||
[u'\u064A', u'\uFEF1', u'\uFEF3', u'\uFEF4', u'\uFEF2', 4],
|
||||
[u'\u066E', u'\uFBE4', u'\uFBE8', u'\uFBE9', u'\uFBE5', 4],
|
||||
[u'\u06AA', u'\uFB8E', u'\uFB90', u'\uFB91', u'\uFB8F', 4],
|
||||
[u'\u06C1', u'\uFBA6', u'\uFBA8', u'\uFBA9', u'\uFBA7', 4],
|
||||
[u'\u067E', u'\uFB56', u'\uFB58', u'\uFB59', u'\uFB57', 4],
|
||||
[u'\u0698', u'\uFB8A', u'\uFB8A', u'\uFB8A', u'\uFB8B', 2],
|
||||
[u'\u06AF', u'\uFB92', u'\uFB94', u'\uFB95', u'\uFB93', 4],
|
||||
[u'\u0686', u'\uFB7A', u'\uFB7C', u'\uFB7D', u'\uFB7B', 4],
|
||||
[u'\u06A9', u'\uFB8E', u'\uFB90', u'\uFB91', u'\uFB8F', 4],
|
||||
[u'\u06CC', u'\uFEEF', u'\uFEF3', u'\uFEF4', u'\uFEF0', 4]
|
||||
]
|
||||
|
||||
|
||||
def get_reshaped_glyph(target, location):
|
||||
if target in ARABIC_GLYPHS:
|
||||
return ARABIC_GLYPHS[target][location]
|
||||
else:
|
||||
return target
|
||||
|
||||
|
||||
def get_glyph_type(target):
|
||||
if target in ARABIC_GLYPHS:
|
||||
return ARABIC_GLYPHS[target][5]
|
||||
else:
|
||||
return 2
|
||||
|
||||
|
||||
def is_haraka(target):
|
||||
return target in HARAKAT
|
||||
|
||||
|
||||
def replace_jalalah(unshaped_word):
|
||||
return re.sub(u'^\u0627\u0644\u0644\u0647$', u'\uFDF2', unshaped_word)
|
||||
|
||||
|
||||
def replace_lam_alef(unshaped_word):
|
||||
list_word = list(unshaped_word)
|
||||
letter_before = u''
|
||||
for i in range(len(unshaped_word)):
|
||||
if not is_haraka(unshaped_word[i]) and unshaped_word[i] != DEFINED_CHARACTERS_ORGINAL_LAM:
|
||||
letter_before = unshaped_word[i]
|
||||
|
||||
if unshaped_word[i] == DEFINED_CHARACTERS_ORGINAL_LAM:
|
||||
candidate_lam = unshaped_word[i]
|
||||
lam_position = i
|
||||
haraka_position = i + 1
|
||||
|
||||
while haraka_position < len(unshaped_word) and is_haraka(unshaped_word[haraka_position]):
|
||||
haraka_position += 1
|
||||
|
||||
if haraka_position < len(unshaped_word):
|
||||
if lam_position > 0 and get_glyph_type(letter_before) > 2:
|
||||
lam_alef = get_lam_alef(
|
||||
list_word[haraka_position], candidate_lam, False)
|
||||
else:
|
||||
lam_alef = get_lam_alef(
|
||||
list_word[haraka_position], candidate_lam, True)
|
||||
if lam_alef != '':
|
||||
list_word[lam_position] = lam_alef
|
||||
list_word[haraka_position] = u' '
|
||||
|
||||
return u''.join(list_word).replace(u' ', u'')
|
||||
|
||||
|
||||
def get_lam_alef(candidate_alef, candidate_lam, is_end_of_word):
|
||||
shift_rate = 1
|
||||
reshaped_lam_alef = u''
|
||||
if is_end_of_word:
|
||||
shift_rate += 1
|
||||
|
||||
if DEFINED_CHARACTERS_ORGINAL_LAM == candidate_lam:
|
||||
if DEFINED_CHARACTERS_ORGINAL_ALF_UPPER_MDD == candidate_alef:
|
||||
reshaped_lam_alef = LAM_ALEF_GLYPHS[0][shift_rate]
|
||||
|
||||
if DEFINED_CHARACTERS_ORGINAL_ALF_UPPER_HAMAZA == candidate_alef:
|
||||
reshaped_lam_alef = LAM_ALEF_GLYPHS[1][shift_rate]
|
||||
|
||||
if DEFINED_CHARACTERS_ORGINAL_ALF == candidate_alef:
|
||||
reshaped_lam_alef = LAM_ALEF_GLYPHS[2][shift_rate]
|
||||
|
||||
if DEFINED_CHARACTERS_ORGINAL_ALF_LOWER_HAMAZA == candidate_alef:
|
||||
reshaped_lam_alef = LAM_ALEF_GLYPHS[3][shift_rate]
|
||||
|
||||
return reshaped_lam_alef
|
||||
|
||||
|
||||
class DecomposedWord(object):
|
||||
|
||||
def __init__(self, word):
|
||||
self.stripped_harakat = []
|
||||
self.harakat_positions = []
|
||||
self.stripped_regular_letters = []
|
||||
self.letters_position = []
|
||||
|
||||
for i in range(len(word)):
|
||||
c = word[i]
|
||||
if is_haraka(c):
|
||||
self.harakat_positions.append(i)
|
||||
self.stripped_harakat.append(c)
|
||||
else:
|
||||
self.letters_position.append(i)
|
||||
self.stripped_regular_letters.append(c)
|
||||
|
||||
def reconstruct_word(self, reshaped_word):
|
||||
l = list(u'\0' * (len(self.stripped_harakat) + len(reshaped_word)))
|
||||
for i in range(len(self.letters_position)):
|
||||
l[self.letters_position[i]] = reshaped_word[i]
|
||||
for i in range(len(self.harakat_positions)):
|
||||
l[self.harakat_positions[i]] = self.stripped_harakat[i]
|
||||
return u''.join(l)
|
||||
|
||||
|
||||
def get_reshaped_word(unshaped_word):
|
||||
unshaped_word = replace_jalalah(unshaped_word)
|
||||
unshaped_word = replace_lam_alef(unshaped_word)
|
||||
decomposed_word = DecomposedWord(unshaped_word)
|
||||
result = u''
|
||||
if decomposed_word.stripped_regular_letters:
|
||||
result = reshape_it(u''.join(decomposed_word.stripped_regular_letters))
|
||||
return decomposed_word.reconstruct_word(result)
|
||||
|
||||
|
||||
def reshape_it(unshaped_word):
|
||||
if not unshaped_word:
|
||||
return u''
|
||||
if len(unshaped_word) == 1:
|
||||
return get_reshaped_glyph(unshaped_word[0], 1)
|
||||
reshaped_word = []
|
||||
for i in range(len(unshaped_word)):
|
||||
before = False
|
||||
after = False
|
||||
if i == 0:
|
||||
after = get_glyph_type(unshaped_word[i]) == 4
|
||||
elif i == len(unshaped_word) - 1:
|
||||
before = get_glyph_type(unshaped_word[i - 1]) == 4
|
||||
else:
|
||||
after = get_glyph_type(unshaped_word[i]) == 4
|
||||
before = get_glyph_type(unshaped_word[i - 1]) == 4
|
||||
if after and before:
|
||||
reshaped_word.append(get_reshaped_glyph(unshaped_word[i], 3))
|
||||
elif after and not before:
|
||||
reshaped_word.append(get_reshaped_glyph(unshaped_word[i], 2))
|
||||
elif not after and before:
|
||||
reshaped_word.append(get_reshaped_glyph(unshaped_word[i], 4))
|
||||
elif not after and not before:
|
||||
reshaped_word.append(get_reshaped_glyph(unshaped_word[i], 1))
|
||||
|
||||
return u''.join(reshaped_word)
|
||||
|
||||
|
||||
def is_arabic_character(target):
|
||||
return target in ARABIC_GLYPHS or target in HARAKAT
|
||||
|
||||
|
||||
def get_words(sentence):
|
||||
if sentence:
|
||||
return re.split('\\s', sentence)
|
||||
return []
|
||||
|
||||
|
||||
def has_arabic_letters(word):
|
||||
for c in word:
|
||||
if is_arabic_character(c):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_arabic_word(word):
|
||||
for c in word:
|
||||
if not is_arabic_character(c):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_words_from_mixed_word(word):
|
||||
temp_word = u''
|
||||
words = []
|
||||
for c in word:
|
||||
if is_arabic_character(c):
|
||||
if temp_word and not is_arabic_word(temp_word):
|
||||
words.append(temp_word)
|
||||
temp_word = c
|
||||
else:
|
||||
temp_word += c
|
||||
else:
|
||||
if temp_word and is_arabic_word(temp_word):
|
||||
words.append(temp_word)
|
||||
temp_word = c
|
||||
else:
|
||||
temp_word += c
|
||||
if temp_word:
|
||||
words.append(temp_word)
|
||||
return words
|
||||
|
||||
|
||||
def reshape(text):
|
||||
if text:
|
||||
lines = re.split('\\r?\\n', text)
|
||||
for i in range(len(lines)):
|
||||
lines[i] = reshape_sentence(lines[i])
|
||||
return u'\n'.join(lines)
|
||||
return u''
|
||||
|
||||
|
||||
def reshape_sentence(sentence):
|
||||
words = get_words(sentence)
|
||||
for i in range(len(words)):
|
||||
word = words[i]
|
||||
if has_arabic_letters(word):
|
||||
if is_arabic_word(word):
|
||||
words[i] = get_reshaped_word(word)
|
||||
else:
|
||||
mixed_words = get_words_from_mixed_word(word)
|
||||
for j in range(len(mixed_words)):
|
||||
mixed_words[j] = get_reshaped_word(mixed_words[j])
|
||||
words[i] = u''.join(mixed_words)
|
||||
return u' '.join(words)
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# import sys
|
||||
#
|
||||
# # reload(sys)
|
||||
# # sys.setdefaultencoding("utf-8")
|
||||
import base64
|
||||
import os
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
# import barcode as barcode
|
||||
from PIL import Image
|
||||
from PIL import ImageDraw
|
||||
from PIL import ImageFont
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from odoo.modules.module import get_module_resource
|
||||
|
||||
|
||||
from lxml import etree
|
||||
|
||||
import arabic_reshaper
|
||||
from bidi.algorithm import get_display
|
||||
from odoo import models, api, fields
|
||||
from odoo.tools.translate import _
|
||||
|
||||
|
||||
# from odoo.osv.orm import setup_modifiers
|
||||
|
||||
|
||||
class Transaction(models.Model):
|
||||
_inherit = 'transaction.transaction'
|
||||
|
||||
binary_barcode = fields.Binary(string='Barcode', attachment=True)
|
||||
|
||||
@api.constrains('ean13', 'name', 'transaction_date', 'type')
|
||||
def binary_compute_constraint(self):
|
||||
fonts = [os.path.dirname(__file__) + '/img/KacstOffice.ttf',
|
||||
os.path.dirname(__file__) + '/img/amiri-regular.ttf']
|
||||
img = Image.new("RGBA", (500, 420), "white")
|
||||
draw = ImageDraw.Draw(img)
|
||||
number_word = "الرقم : "
|
||||
number_word_reshaped = arabic_reshaper.reshape(
|
||||
u'' + number_word)
|
||||
number_word_artext = get_display(number_word_reshaped)
|
||||
draw.text((220, 20),
|
||||
number_word_artext, "black",
|
||||
font=ImageFont.truetype(fonts[1], 18))
|
||||
|
||||
number_value = self.name
|
||||
number_value_reshaped = arabic_reshaper.reshape(
|
||||
u'' + number_value if number_value else '')
|
||||
number_value_artext = get_display(number_value_reshaped)
|
||||
draw.text((80, 20),
|
||||
number_value_artext, "black",
|
||||
font=ImageFont.truetype(fonts[1], 18))
|
||||
#
|
||||
date_hijri = "التاريخ : "
|
||||
date_hijri_reshaped = arabic_reshaper.reshape(
|
||||
u'' + date_hijri)
|
||||
date_hijri_artext = get_display(date_hijri_reshaped)
|
||||
draw.text((211, 40),
|
||||
date_hijri_artext, "black",
|
||||
font=ImageFont.truetype(fonts[1], 18))
|
||||
|
||||
date_hijri_value = self.transaction_date_hijri
|
||||
date_hijri_value_reshaped = arabic_reshaper.reshape(
|
||||
u'' + date_hijri_value if date_hijri_value else '')
|
||||
date_hijri_artext = get_display(date_hijri_value_reshaped)
|
||||
draw.text((120, 40),
|
||||
date_hijri_artext.replace('-', '/'), "black",
|
||||
font=ImageFont.truetype(fonts[1], 18))
|
||||
|
||||
date_m = "الموافق : "
|
||||
date_m_reshaped = arabic_reshaper.reshape(
|
||||
u'' + date_m)
|
||||
date_m_artext = get_display(date_m_reshaped)
|
||||
draw.text((210, 65),
|
||||
date_m_artext, "black",
|
||||
font=ImageFont.truetype(fonts[1], 18))
|
||||
|
||||
date_m_value = self.transaction_date
|
||||
date_m_value_reshaped = arabic_reshaper.reshape(
|
||||
u'' + str(date_m_value) if date_m_value else '')
|
||||
date_m_value_artext = get_display(date_m_value_reshaped)
|
||||
draw.text((120, 65),
|
||||
date_m_value_artext.replace('-', '/'), "black",
|
||||
font=ImageFont.truetype(fonts[1], 18))
|
||||
|
||||
attach_m = "المرفقات : "
|
||||
attach_m_reshaped = arabic_reshaper.reshape(
|
||||
u'' + attach_m)
|
||||
date_m_artext = get_display(attach_m_reshaped)
|
||||
draw.text((200, 85),
|
||||
date_m_artext, "black",
|
||||
font=ImageFont.truetype(fonts[1], 18))
|
||||
|
||||
attach_m_value = str(self.attachment_num) if self.attachment_num else '0'
|
||||
attach_m_value_reshaped = arabic_reshaper.reshape(
|
||||
u'' + attach_m_value)
|
||||
attach_mvalue_artext = get_display(attach_m_value_reshaped)
|
||||
draw.text((180, 85),
|
||||
attach_mvalue_artext, "black",
|
||||
font=ImageFont.truetype(fonts[1], 18))
|
||||
# barcode_symbology = options.get('symbology', 'Code128')
|
||||
barcode = self.env['ir.actions.report'].barcode('Code11', self.name, width=250, height=100,
|
||||
humanreadable=0)
|
||||
|
||||
|
||||
|
||||
barcode_buffer = BytesIO(barcode)
|
||||
barcode_image_file = Image.open(barcode_buffer)
|
||||
ImageDraw.Draw(img)
|
||||
buffered = BytesIO()
|
||||
img.paste(barcode_image_file, (20, 110))
|
||||
img.save(buffered, format="png")
|
||||
img_str = base64.b64encode(buffered.getvalue())
|
||||
self.binary_barcode = img_str
|
||||
|
||||
|
||||
class AttachmentInherit(models.Model):
|
||||
_inherit = 'ir.attachment'
|
||||
|
||||
# @api.constrains('vals_list')
|
||||
# def create(self, vals_list):
|
||||
# print("***********")
|
||||
# res = super(AttachmentInherit, self).create(vals_list)
|
||||
# print(res.mimetype)
|
||||
# if res.mimetype == 'text/html':
|
||||
# raise ValidationError(_('You cannot inset a html File'))
|
||||
#
|
||||
# return res
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env python
|
||||
# This file is part of python-bidi
|
||||
#
|
||||
# python-bidi is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Copyright (C) 2008-2010 Yaacov Zamir <kzamir_a_walla.co.il>,
|
||||
# Copyright (C) 2010-2015 Meir kriheli <mkriheli@gmail.com>.
|
||||
|
||||
"""
|
||||
Implementation of Unicode Bidirectional Algorithm
|
||||
http://www.unicode.org/unicode/reports/tr9/
|
||||
"""
|
||||
|
||||
VERSION = '0.4.0'
|
||||
|
||||
|
||||
def main():
|
||||
"""Will be used to create the console script"""
|
||||
|
||||
import optparse
|
||||
import sys
|
||||
import codecs
|
||||
import locale
|
||||
import six
|
||||
from .algorithm import get_display
|
||||
|
||||
parser = optparse.OptionParser()
|
||||
|
||||
parser.add_option('-e', '--encoding',
|
||||
dest='encoding',
|
||||
default='utf-8',
|
||||
type='string',
|
||||
help='Text encoding (default: utf-8)')
|
||||
|
||||
parser.add_option('-u', '--upper-is-rtl',
|
||||
dest='upper_is_rtl',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help="Treat upper case chars as strong 'R' "
|
||||
'for debugging (default: False).')
|
||||
|
||||
parser.add_option('-d', '--debug',
|
||||
dest='debug',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help="Output to stderr steps taken with the algorithm")
|
||||
|
||||
parser.add_option('-b', '--base-dir',
|
||||
dest='base_dir',
|
||||
default=None,
|
||||
type='string',
|
||||
help="Override base direction [L|R]")
|
||||
|
||||
options, rest = parser.parse_args()
|
||||
|
||||
if options.base_dir and options.base_dir not in 'LR':
|
||||
parser.error('option -b can be L or R')
|
||||
|
||||
# allow unicode in sys.stdout.write
|
||||
if six.PY2:
|
||||
sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
|
||||
|
||||
if rest:
|
||||
lines = rest
|
||||
else:
|
||||
lines = sys.stdin
|
||||
|
||||
for line in lines:
|
||||
display = get_display(line, options.encoding, options.upper_is_rtl,
|
||||
options.base_dir, options.debug)
|
||||
# adjust the encoding as unicode, to match the output encoding
|
||||
if not isinstance(display, six.text_type):
|
||||
display = display.decode(options.encoding)
|
||||
|
||||
six.print_(display, end='')
|
||||
|
|
@ -0,0 +1,658 @@
|
|||
# This file is part of python-bidi
|
||||
#
|
||||
# python-bidi is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Copyright (C) 2008-2010 Yaacov Zamir <kzamir_a_walla.co.il>,
|
||||
# Copyright (C) 2010-2015 Meir kriheli <mkriheli@gmail.com>.
|
||||
"bidirectional alogrithm implementation"
|
||||
import sys
|
||||
|
||||
import inspect
|
||||
from collections import deque
|
||||
from unicodedata import bidirectional, mirrored
|
||||
import six
|
||||
|
||||
from .mirror import MIRRORED
|
||||
|
||||
|
||||
# Some definitions
|
||||
PARAGRAPH_LEVELS = {'L': 0, 'AL': 1, 'R': 1}
|
||||
EXPLICIT_LEVEL_LIMIT = 62
|
||||
|
||||
|
||||
def _LEAST_GREATER_ODD(x):
|
||||
return (x + 1) | 1
|
||||
|
||||
|
||||
def _LEAST_GREATER_EVEN(x):
|
||||
return (x + 2) & ~1
|
||||
|
||||
|
||||
X2_X5_MAPPINGS = {
|
||||
'RLE': (_LEAST_GREATER_ODD, 'N'),
|
||||
'LRE': (_LEAST_GREATER_EVEN, 'N'),
|
||||
'RLO': (_LEAST_GREATER_ODD, 'R'),
|
||||
'LRO': (_LEAST_GREATER_EVEN, 'L'),
|
||||
}
|
||||
|
||||
# Added 'B' so X6 won't execute in that case and X8 will run it's course
|
||||
X6_IGNORED = list(X2_X5_MAPPINGS.keys()) + ['BN', 'PDF', 'B']
|
||||
X9_REMOVED = list(X2_X5_MAPPINGS.keys()) + ['BN', 'PDF']
|
||||
|
||||
|
||||
def _embedding_direction(x):
|
||||
return ('L', 'R')[x % 2]
|
||||
|
||||
|
||||
_IS_UCS2 = sys.maxunicode == 65535
|
||||
_SURROGATE_MIN, _SURROGATE_MAX = 55296, 56319 # D800, DBFF
|
||||
|
||||
|
||||
def debug_storage(storage, base_info=False, chars=True, runs=False):
|
||||
"Display debug information for the storage"
|
||||
|
||||
import codecs
|
||||
import locale
|
||||
import sys
|
||||
|
||||
if six.PY2:
|
||||
stderr = codecs.getwriter(locale.getpreferredencoding())(sys.stderr)
|
||||
else:
|
||||
stderr = sys.stderr
|
||||
|
||||
caller = inspect.stack()[1][3]
|
||||
stderr.write('in %s\n' % caller)
|
||||
|
||||
if base_info:
|
||||
stderr.write(u' base level : %d\n' % storage['base_level'])
|
||||
stderr.write(u' base dir : %s\n' % storage['base_dir'])
|
||||
|
||||
if runs:
|
||||
stderr.write(u' runs : %s\n' % list(storage['runs']))
|
||||
|
||||
if chars:
|
||||
output = u' Chars : '
|
||||
for _ch in storage['chars']:
|
||||
if _ch != '\n':
|
||||
output += _ch['ch']
|
||||
else:
|
||||
output += 'C'
|
||||
stderr.write(output + u'\n')
|
||||
|
||||
output = u' Res. levels : %s\n' % u''.join(
|
||||
[six.text_type(_ch['level']) for _ch in storage['chars']])
|
||||
stderr.write(output)
|
||||
|
||||
_types = [_ch['type'].ljust(3) for _ch in storage['chars']]
|
||||
|
||||
for i in range(3):
|
||||
if i:
|
||||
output = u' %s\n'
|
||||
else:
|
||||
output = u' Res. types : %s\n'
|
||||
stderr.write(output % u''.join([_t[i] for _t in _types]))
|
||||
|
||||
|
||||
def get_base_level(text, upper_is_rtl=False):
|
||||
"""Get the paragraph base embedding level. Returns 0 for LTR,
|
||||
1 for RTL.
|
||||
|
||||
`text` a unicode object.
|
||||
|
||||
Set `upper_is_rtl` to True to treat upper case chars as strong 'R'
|
||||
for debugging (default: False).
|
||||
|
||||
"""
|
||||
|
||||
base_level = None
|
||||
|
||||
prev_surrogate = False
|
||||
# P2
|
||||
for _ch in text:
|
||||
# surrogate in case of ucs2
|
||||
if _IS_UCS2 and (_SURROGATE_MIN <= ord(_ch) <= _SURROGATE_MAX):
|
||||
prev_surrogate = _ch
|
||||
continue
|
||||
elif prev_surrogate:
|
||||
_ch = prev_surrogate + _ch
|
||||
prev_surrogate = False
|
||||
|
||||
# treat upper as RTL ?
|
||||
if upper_is_rtl and _ch.isupper():
|
||||
base_level = 1
|
||||
break
|
||||
|
||||
bidi_type = bidirectional(_ch)
|
||||
|
||||
if bidi_type in ('AL', 'R'):
|
||||
base_level = 1
|
||||
break
|
||||
|
||||
elif bidi_type == 'L':
|
||||
base_level = 0
|
||||
break
|
||||
|
||||
# P3
|
||||
if base_level is None:
|
||||
base_level = 0
|
||||
|
||||
return base_level
|
||||
|
||||
|
||||
def get_embedding_levels(text, storage, upper_is_rtl=False, debug=False):
|
||||
"""Get the paragraph base embedding level and direction,
|
||||
set the storage to the array of chars"""
|
||||
|
||||
prev_surrogate = False
|
||||
base_level = storage['base_level']
|
||||
|
||||
# preset the storage's chars
|
||||
for _ch in text:
|
||||
if _IS_UCS2 and (_SURROGATE_MIN <= ord(_ch) <= _SURROGATE_MAX):
|
||||
prev_surrogate = _ch
|
||||
continue
|
||||
elif prev_surrogate:
|
||||
_ch = prev_surrogate + _ch
|
||||
prev_surrogate = False
|
||||
|
||||
if upper_is_rtl and _ch.isupper():
|
||||
bidi_type = 'R'
|
||||
else:
|
||||
bidi_type = bidirectional(_ch)
|
||||
|
||||
storage['chars'].append({
|
||||
'ch': _ch,
|
||||
'level': base_level,
|
||||
'type': bidi_type,
|
||||
'orig': bidi_type
|
||||
})
|
||||
if debug:
|
||||
debug_storage(storage, base_info=True)
|
||||
|
||||
|
||||
def explicit_embed_and_overrides(storage, debug=False):
|
||||
"""Apply X1 to X9 rules of the unicode algorithm.
|
||||
|
||||
See http://unicode.org/reports/tr9/#Explicit_Levels_and_Directions
|
||||
|
||||
"""
|
||||
overflow_counter = almost_overflow_counter = 0
|
||||
directional_override = 'N'
|
||||
levels = deque()
|
||||
|
||||
# X1
|
||||
embedding_level = storage['base_level']
|
||||
|
||||
for _ch in storage['chars']:
|
||||
bidi_type = _ch['type']
|
||||
|
||||
level_func, override = X2_X5_MAPPINGS.get(bidi_type, (None, None))
|
||||
|
||||
if level_func:
|
||||
# So this is X2 to X5
|
||||
# if we've past EXPLICIT_LEVEL_LIMIT, note it and do nothing
|
||||
|
||||
if overflow_counter != 0:
|
||||
overflow_counter += 1
|
||||
continue
|
||||
|
||||
new_level = level_func(embedding_level)
|
||||
if new_level < EXPLICIT_LEVEL_LIMIT:
|
||||
levels.append((embedding_level, directional_override))
|
||||
embedding_level, directional_override = new_level, override
|
||||
|
||||
elif embedding_level == EXPLICIT_LEVEL_LIMIT - 2:
|
||||
# The new level is invalid, but a valid level can still be
|
||||
# achieved if this level is 60 and we encounter an RLE or
|
||||
# RLO further on. So record that we 'almost' overflowed.
|
||||
almost_overflow_counter += 1
|
||||
|
||||
else:
|
||||
overflow_counter += 1
|
||||
else:
|
||||
# X6
|
||||
if bidi_type not in X6_IGNORED:
|
||||
_ch['level'] = embedding_level
|
||||
if directional_override != 'N':
|
||||
_ch['type'] = directional_override
|
||||
|
||||
# X7
|
||||
elif bidi_type == 'PDF':
|
||||
if overflow_counter:
|
||||
overflow_counter -= 1
|
||||
elif almost_overflow_counter and \
|
||||
embedding_level != EXPLICIT_LEVEL_LIMIT - 1:
|
||||
almost_overflow_counter -= 1
|
||||
elif levels:
|
||||
embedding_level, directional_override = levels.pop()
|
||||
|
||||
# X8
|
||||
elif bidi_type == 'B':
|
||||
levels.clear()
|
||||
overflow_counter = almost_overflow_counter = 0
|
||||
embedding_level = _ch['level'] = storage['base_level']
|
||||
directional_override = 'N'
|
||||
|
||||
# Removes the explicit embeds and overrides of types
|
||||
# RLE, LRE, RLO, LRO, PDF, and BN. Adjusts extended chars
|
||||
# next and prev as well
|
||||
|
||||
# Applies X9. See http://unicode.org/reports/tr9/#X9
|
||||
storage['chars'] = [_ch for _ch in storage['chars']
|
||||
if _ch['type'] not in X9_REMOVED]
|
||||
|
||||
calc_level_runs(storage)
|
||||
|
||||
if debug:
|
||||
debug_storage(storage, runs=True)
|
||||
|
||||
|
||||
def calc_level_runs(storage):
|
||||
"""Split the storage to run of char types at the same level.
|
||||
|
||||
Applies X10. See http://unicode.org/reports/tr9/#X10
|
||||
"""
|
||||
# run level depends on the higher of the two levels on either side of
|
||||
# the boundary If the higher level is odd, the type is R; otherwise,
|
||||
# it is L
|
||||
|
||||
storage['runs'].clear()
|
||||
chars = storage['chars']
|
||||
|
||||
# empty string ?
|
||||
if not chars:
|
||||
return
|
||||
|
||||
def calc_level_run(b_l, b_r):
|
||||
return ['L', 'R'][max(b_l, b_r) % 2]
|
||||
|
||||
first_char = chars[0]
|
||||
|
||||
sor = calc_level_run(storage['base_level'], first_char['level'])
|
||||
eor = None
|
||||
|
||||
run_start = run_length = 0
|
||||
|
||||
prev_level, prev_type = first_char['level'], first_char['type']
|
||||
|
||||
for _ch in chars:
|
||||
curr_level, curr_type = _ch['level'], _ch['type']
|
||||
|
||||
if curr_level == prev_level:
|
||||
run_length += 1
|
||||
else:
|
||||
eor = calc_level_run(prev_level, curr_level)
|
||||
storage['runs'].append({'sor': sor, 'eor': eor, 'start': run_start,
|
||||
'type': prev_type, 'length': run_length})
|
||||
sor = eor
|
||||
run_start += run_length
|
||||
run_length = 1
|
||||
|
||||
prev_level, prev_type = curr_level, curr_type
|
||||
|
||||
# for the last char/runlevel
|
||||
eor = calc_level_run(curr_level, storage['base_level'])
|
||||
storage['runs'].append({'sor': sor, 'eor': eor, 'start': run_start,
|
||||
'type': curr_type, 'length': run_length})
|
||||
|
||||
|
||||
def resolve_weak_types(storage, debug=False):
|
||||
"""Reslove weak type rules W1 - W3.
|
||||
|
||||
See: http://unicode.org/reports/tr9/#Resolving_Weak_Types
|
||||
|
||||
"""
|
||||
|
||||
for run in storage['runs']:
|
||||
prev_strong = prev_type = run['sor']
|
||||
start, length = run['start'], run['length']
|
||||
chars = storage['chars'][start:start + length]
|
||||
for _ch in chars:
|
||||
# W1. Examine each nonspacing mark (NSM) in the level run, and
|
||||
# change the type of the NSM to the type of the previous character.
|
||||
# If the NSM is at the start of the level run, it will get the type
|
||||
# of sor.
|
||||
bidi_type = _ch['type']
|
||||
|
||||
if bidi_type == 'NSM':
|
||||
_ch['type'] = bidi_type = prev_type
|
||||
|
||||
# W2. Search backward from each instance of a European number until
|
||||
# the first strong type (R, L, AL, or sor) is found. If an AL is
|
||||
# found, change the type of the European number to Arabic number.
|
||||
if bidi_type == 'EN' and prev_strong == 'AL':
|
||||
_ch['type'] = 'AN'
|
||||
|
||||
# update prev_strong if needed
|
||||
if bidi_type in ('R', 'L', 'AL'):
|
||||
prev_strong = bidi_type
|
||||
|
||||
prev_type = _ch['type']
|
||||
|
||||
# W3. Change all ALs to R
|
||||
for _ch in chars:
|
||||
if _ch['type'] == 'AL':
|
||||
_ch['type'] = 'R'
|
||||
|
||||
# W4. A single European separator between two European numbers changes
|
||||
# to a European number. A single common separator between two numbers of
|
||||
# the same type changes to that type.
|
||||
for idx in range(1, len(chars) - 1):
|
||||
bidi_type = chars[idx]['type']
|
||||
prev_type = chars[idx - 1]['type']
|
||||
next_type = chars[idx + 1]['type']
|
||||
|
||||
if bidi_type == 'ES' and (prev_type == next_type == 'EN'):
|
||||
chars[idx]['type'] = 'EN'
|
||||
|
||||
if bidi_type == 'CS' and prev_type == next_type and \
|
||||
prev_type in ('AN', 'EN'):
|
||||
chars[idx]['type'] = prev_type
|
||||
|
||||
# W5. A sequence of European terminators adjacent to European numbers
|
||||
# changes to all European numbers.
|
||||
for idx in range(len(chars)):
|
||||
if chars[idx]['type'] == 'EN':
|
||||
for et_idx in range(idx - 1, -1, -1):
|
||||
if chars[et_idx]['type'] == 'ET':
|
||||
chars[et_idx]['type'] = 'EN'
|
||||
else:
|
||||
break
|
||||
for et_idx in range(idx + 1, len(chars)):
|
||||
if chars[et_idx]['type'] == 'ET':
|
||||
chars[et_idx]['type'] = 'EN'
|
||||
else:
|
||||
break
|
||||
|
||||
# W6. Otherwise, separators and terminators change to Other Neutral.
|
||||
for _ch in chars:
|
||||
if _ch['type'] in ('ET', 'ES', 'CS'):
|
||||
_ch['type'] = 'ON'
|
||||
|
||||
# W7. Search backward from each instance of a European number until the
|
||||
# first strong type (R, L, or sor) is found. If an L is found, then
|
||||
# change the type of the European number to L.
|
||||
prev_strong = run['sor']
|
||||
for _ch in chars:
|
||||
if _ch['type'] == 'EN' and prev_strong == 'L':
|
||||
_ch['type'] = 'L'
|
||||
|
||||
if _ch['type'] in ('L', 'R'):
|
||||
prev_strong = _ch['type']
|
||||
|
||||
if debug:
|
||||
debug_storage(storage, runs=True)
|
||||
|
||||
|
||||
def resolve_neutral_types(storage, debug):
|
||||
"""Resolving neutral types. Implements N1 and N2
|
||||
|
||||
See: http://unicode.org/reports/tr9/#Resolving_Neutral_Types
|
||||
|
||||
"""
|
||||
|
||||
for run in storage['runs']:
|
||||
start, length = run['start'], run['length']
|
||||
# use sor and eor
|
||||
chars = [{'type': run['sor']}] + storage['chars'][start:start + length] + \
|
||||
[{'type': run['eor']}]
|
||||
total_chars = len(chars)
|
||||
|
||||
seq_start = None
|
||||
for idx in range(total_chars):
|
||||
_ch = chars[idx]
|
||||
if _ch['type'] in ('B', 'S', 'WS', 'ON'):
|
||||
# N1. A sequence of neutrals takes the direction of the
|
||||
# surrounding strong text if the text on both sides has the same
|
||||
# direction. European and Arabic numbers act as if they were R
|
||||
# in terms of their influence on neutrals. Start-of-level-run
|
||||
# (sor) and end-of-level-run (eor) are used at level run
|
||||
# boundaries.
|
||||
if seq_start is None:
|
||||
seq_start = idx
|
||||
prev_bidi_type = chars[idx - 1]['type']
|
||||
else:
|
||||
if seq_start is not None:
|
||||
next_bidi_type = chars[idx]['type']
|
||||
|
||||
if prev_bidi_type in ('AN', 'EN'):
|
||||
prev_bidi_type = 'R'
|
||||
|
||||
if next_bidi_type in ('AN', 'EN'):
|
||||
next_bidi_type = 'R'
|
||||
|
||||
for seq_idx in range(seq_start, idx):
|
||||
if prev_bidi_type == next_bidi_type:
|
||||
chars[seq_idx]['type'] = prev_bidi_type
|
||||
else:
|
||||
# N2. Any remaining neutrals take the embedding
|
||||
# direction. The embedding direction for the given
|
||||
# neutral character is derived from its embedding
|
||||
# level: L if the character is set to an even level,
|
||||
# and R if the level is odd.
|
||||
chars[seq_idx]['type'] = \
|
||||
_embedding_direction(chars[seq_idx]['level'])
|
||||
|
||||
seq_start = None
|
||||
|
||||
if debug:
|
||||
debug_storage(storage)
|
||||
|
||||
|
||||
def resolve_implicit_levels(storage, debug):
|
||||
"""Resolving implicit levels (I1, I2)
|
||||
|
||||
See: http://unicode.org/reports/tr9/#Resolving_Implicit_Levels
|
||||
|
||||
"""
|
||||
for run in storage['runs']:
|
||||
start, length = run['start'], run['length']
|
||||
chars = storage['chars'][start:start + length]
|
||||
|
||||
for _ch in chars:
|
||||
# only those types are allowed at this stage
|
||||
assert _ch['type'] in ('L', 'R', 'EN', 'AN'), \
|
||||
'%s not allowed here' % _ch['type']
|
||||
|
||||
if _embedding_direction(_ch['level']) == 'L':
|
||||
# I1. For all characters with an even (left-to-right) embedding
|
||||
# direction, those of type R go up one level and those of type
|
||||
# AN or EN go up two levels.
|
||||
if _ch['type'] == 'R':
|
||||
_ch['level'] += 1
|
||||
elif _ch['type'] != 'L':
|
||||
_ch['level'] += 2
|
||||
else:
|
||||
# I2. For all characters with an odd (right-to-left) embedding
|
||||
# direction, those of type L, EN or AN go up one level.
|
||||
if _ch['type'] != 'R':
|
||||
_ch['level'] += 1
|
||||
|
||||
if debug:
|
||||
debug_storage(storage, runs=True)
|
||||
|
||||
|
||||
def reverse_contiguous_sequence(chars, line_start, line_end, highest_level,
|
||||
lowest_odd_level):
|
||||
"""L2. From the highest level found in the text to the lowest odd
|
||||
level on each line, including intermediate levels not actually
|
||||
present in the text, reverse any contiguous sequence of characters
|
||||
that are at that level or higher.
|
||||
|
||||
"""
|
||||
for level in range(highest_level, lowest_odd_level - 1, -1):
|
||||
_start = _end = None
|
||||
|
||||
for run_idx in range(line_start, line_end + 1):
|
||||
run_ch = chars[run_idx]
|
||||
|
||||
if run_ch['level'] >= level:
|
||||
if _start is None:
|
||||
_start = _end = run_idx
|
||||
else:
|
||||
_end = run_idx
|
||||
else:
|
||||
if _end:
|
||||
chars[_start:+_end + 1] = \
|
||||
reversed(chars[_start:+_end + 1])
|
||||
_start = _end = None
|
||||
|
||||
# anything remaining ?
|
||||
if _start is not None:
|
||||
chars[_start:+_end + 1] = \
|
||||
reversed(chars[_start:+_end + 1])
|
||||
|
||||
|
||||
def reorder_resolved_levels(storage, debug):
|
||||
"""L1 and L2 rules"""
|
||||
|
||||
# Applies L1.
|
||||
|
||||
should_reset = True
|
||||
chars = storage['chars']
|
||||
|
||||
for _ch in chars[::-1]:
|
||||
# L1. On each line, reset the embedding level of the following
|
||||
# characters to the paragraph embedding level:
|
||||
if _ch['orig'] in ('B', 'S'):
|
||||
# 1. Segment separators,
|
||||
# 2. Paragraph separators,
|
||||
_ch['level'] = storage['base_level']
|
||||
should_reset = True
|
||||
elif should_reset and _ch['orig'] in ('BN', 'WS'):
|
||||
# 3. Any sequence of whitespace characters preceding a segment
|
||||
# separator or paragraph separator
|
||||
# 4. Any sequence of white space characters at the end of the
|
||||
# line.
|
||||
_ch['level'] = storage['base_level']
|
||||
else:
|
||||
should_reset = False
|
||||
|
||||
max_len = len(chars)
|
||||
|
||||
# L2 should be per line
|
||||
# Calculates highest level and loweset odd level on the fly.
|
||||
|
||||
line_start = line_end = 0
|
||||
highest_level = 0
|
||||
lowest_odd_level = EXPLICIT_LEVEL_LIMIT
|
||||
|
||||
for idx in range(max_len):
|
||||
_ch = chars[idx]
|
||||
|
||||
# calc the levels
|
||||
char_level = _ch['level']
|
||||
if char_level > highest_level:
|
||||
highest_level = char_level
|
||||
|
||||
if char_level % 2 and char_level < lowest_odd_level:
|
||||
lowest_odd_level = char_level
|
||||
|
||||
if _ch['orig'] == 'B' or idx == max_len - 1:
|
||||
line_end = idx
|
||||
# omit line breaks
|
||||
if _ch['orig'] == 'B':
|
||||
line_end -= 1
|
||||
|
||||
reverse_contiguous_sequence(chars, line_start, line_end,
|
||||
highest_level, lowest_odd_level)
|
||||
|
||||
# reset for next line run
|
||||
line_start = idx + 1
|
||||
highest_level = 0
|
||||
lowest_odd_level = EXPLICIT_LEVEL_LIMIT
|
||||
|
||||
if debug:
|
||||
debug_storage(storage)
|
||||
|
||||
|
||||
def apply_mirroring(storage, debug):
|
||||
"""Applies L4: mirroring
|
||||
|
||||
See: http://unicode.org/reports/tr9/#L4
|
||||
|
||||
"""
|
||||
# L4. A character is depicted by a mirrored glyph if and only if (a) the
|
||||
# resolved directionality of that character is R, and (b) the
|
||||
# Bidi_Mirrored property value of that character is true.
|
||||
for _ch in storage['chars']:
|
||||
unichar = _ch['ch']
|
||||
if mirrored(unichar) and \
|
||||
_embedding_direction(_ch['level']) == 'R':
|
||||
_ch['ch'] = MIRRORED.get(unichar, unichar)
|
||||
|
||||
if debug:
|
||||
debug_storage(storage)
|
||||
|
||||
|
||||
def get_empty_storage():
|
||||
"""Return an empty storage skeleton, usable for testing"""
|
||||
return {
|
||||
'base_level': None,
|
||||
'base_dir': None,
|
||||
'chars': [],
|
||||
'runs': deque(),
|
||||
}
|
||||
|
||||
|
||||
def get_display(unicode_or_str, encoding='utf-8', upper_is_rtl=False,
|
||||
base_dir=None, debug=False):
|
||||
"""Accepts unicode or string. In case it's a string, `encoding`
|
||||
is needed as it works on unicode ones (default:"utf-8").
|
||||
|
||||
Set `upper_is_rtl` to True to treat upper case chars as strong 'R'
|
||||
for debugging (default: False).
|
||||
|
||||
Set `base_dir` to 'L' or 'R' to override the calculated base_level.
|
||||
|
||||
Set `debug` to True to display (using sys.stderr) the steps taken with the
|
||||
algorithm.
|
||||
|
||||
Returns the display layout, either as unicode or `encoding` encoded
|
||||
string.
|
||||
|
||||
"""
|
||||
storage = get_empty_storage()
|
||||
|
||||
# utf-8 ? we need unicode
|
||||
if isinstance(unicode_or_str, six.text_type):
|
||||
text = unicode_or_str
|
||||
decoded = False
|
||||
else:
|
||||
text = unicode_or_str.decode(encoding)
|
||||
decoded = True
|
||||
|
||||
if base_dir is None:
|
||||
base_level = get_base_level(text, upper_is_rtl)
|
||||
else:
|
||||
base_level = PARAGRAPH_LEVELS[base_dir]
|
||||
|
||||
storage['base_level'] = base_level
|
||||
storage['base_dir'] = ('L', 'R')[base_level]
|
||||
|
||||
get_embedding_levels(text, storage, upper_is_rtl, debug)
|
||||
explicit_embed_and_overrides(storage, debug)
|
||||
resolve_weak_types(storage, debug)
|
||||
resolve_neutral_types(storage, debug)
|
||||
resolve_implicit_levels(storage, debug)
|
||||
reorder_resolved_levels(storage, debug)
|
||||
apply_mirroring(storage, debug)
|
||||
|
||||
chars = storage['chars']
|
||||
display = u''.join([_ch['ch'] for _ch in chars])
|
||||
|
||||
if decoded:
|
||||
return display.encode(encoding)
|
||||
else:
|
||||
return display
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
# This file is part of python-bidi
|
||||
#
|
||||
# python-bidi is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Copyright (C) 2008-2010 Yaacov Zamir <kzamir_a_walla.co.il>,
|
||||
# Copyright (C) 2010-2015 Meir kriheli <mkriheli@gmail.com>.
|
||||
"""Mirrored chars"""
|
||||
|
||||
# Can't seem to get this data from python's unicode data, so this is imported
|
||||
# from http://www.unicode.org/Public/UNIDATA/BidiMirroring.txt
|
||||
MIRRORED = {
|
||||
u'\u0028': u'\u0029', # LEFT PARENTHESIS
|
||||
u'\u0029': u'\u0028', # RIGHT PARENTHESIS
|
||||
u'\u003C': u'\u003E', # LESS-THAN SIGN
|
||||
u'\u003E': u'\u003C', # GREATER-THAN SIGN
|
||||
u'\u005B': u'\u005D', # LEFT SQUARE BRACKET
|
||||
u'\u005D': u'\u005B', # RIGHT SQUARE BRACKET
|
||||
u'\u007B': u'\u007D', # LEFT CURLY BRACKET
|
||||
u'\u007D': u'\u007B', # RIGHT CURLY BRACKET
|
||||
u'\u00AB': u'\u00BB', # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
u'\u00BB': u'\u00AB', # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
u'\u0F3A': u'\u0F3B', # TIBETAN MARK GUG RTAGS GYON
|
||||
u'\u0F3B': u'\u0F3A', # TIBETAN MARK GUG RTAGS GYAS
|
||||
u'\u0F3C': u'\u0F3D', # TIBETAN MARK ANG KHANG GYON
|
||||
u'\u0F3D': u'\u0F3C', # TIBETAN MARK ANG KHANG GYAS
|
||||
u'\u169B': u'\u169C', # OGHAM FEATHER MARK
|
||||
u'\u169C': u'\u169B', # OGHAM REVERSED FEATHER MARK
|
||||
u'\u2039': u'\u203A', # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
u'\u203A': u'\u2039', # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
u'\u2045': u'\u2046', # LEFT SQUARE BRACKET WITH QUILL
|
||||
u'\u2046': u'\u2045', # RIGHT SQUARE BRACKET WITH QUILL
|
||||
u'\u207D': u'\u207E', # SUPERSCRIPT LEFT PARENTHESIS
|
||||
u'\u207E': u'\u207D', # SUPERSCRIPT RIGHT PARENTHESIS
|
||||
u'\u208D': u'\u208E', # SUBSCRIPT LEFT PARENTHESIS
|
||||
u'\u208E': u'\u208D', # SUBSCRIPT RIGHT PARENTHESIS
|
||||
u'\u2208': u'\u220B', # ELEMENT OF
|
||||
u'\u2209': u'\u220C', # NOT AN ELEMENT OF
|
||||
u'\u220A': u'\u220D', # SMALL ELEMENT OF
|
||||
u'\u220B': u'\u2208', # CONTAINS AS MEMBER
|
||||
u'\u220C': u'\u2209', # DOES NOT CONTAIN AS MEMBER
|
||||
u'\u220D': u'\u220A', # SMALL CONTAINS AS MEMBER
|
||||
u'\u2215': u'\u29F5', # DIVISION SLASH
|
||||
u'\u223C': u'\u223D', # TILDE OPERATOR
|
||||
u'\u223D': u'\u223C', # REVERSED TILDE
|
||||
u'\u2243': u'\u22CD', # ASYMPTOTICALLY EQUAL TO
|
||||
u'\u2252': u'\u2253', # APPROXIMATELY EQUAL TO OR THE IMAGE OF
|
||||
u'\u2253': u'\u2252', # IMAGE OF OR APPROXIMATELY EQUAL TO
|
||||
u'\u2254': u'\u2255', # COLON EQUALS
|
||||
u'\u2255': u'\u2254', # EQUALS COLON
|
||||
u'\u2264': u'\u2265', # LESS-THAN OR EQUAL TO
|
||||
u'\u2265': u'\u2264', # GREATER-THAN OR EQUAL TO
|
||||
u'\u2266': u'\u2267', # LESS-THAN OVER EQUAL TO
|
||||
u'\u2267': u'\u2266', # GREATER-THAN OVER EQUAL TO
|
||||
u'\u2268': u'\u2269', # [BEST FIT] LESS-THAN BUT NOT EQUAL TO
|
||||
u'\u2269': u'\u2268', # [BEST FIT] GREATER-THAN BUT NOT EQUAL TO
|
||||
u'\u226A': u'\u226B', # MUCH LESS-THAN
|
||||
u'\u226B': u'\u226A', # MUCH GREATER-THAN
|
||||
u'\u226E': u'\u226F', # [BEST FIT] NOT LESS-THAN
|
||||
u'\u226F': u'\u226E', # [BEST FIT] NOT GREATER-THAN
|
||||
u'\u2270': u'\u2271', # [BEST FIT] NEITHER LESS-THAN NOR EQUAL TO
|
||||
u'\u2271': u'\u2270', # [BEST FIT] NEITHER GREATER-THAN NOR EQUAL TO
|
||||
u'\u2272': u'\u2273', # [BEST FIT] LESS-THAN OR EQUIVALENT TO
|
||||
u'\u2273': u'\u2272', # [BEST FIT] GREATER-THAN OR EQUIVALENT TO
|
||||
u'\u2274': u'\u2275', # [BEST FIT] NEITHER LESS-THAN NOR EQUIVALENT TO
|
||||
u'\u2275': u'\u2274', # [BEST FIT] NEITHER GREATER-THAN NOR EQUIVALENT TO
|
||||
u'\u2276': u'\u2277', # LESS-THAN OR GREATER-THAN
|
||||
u'\u2277': u'\u2276', # GREATER-THAN OR LESS-THAN
|
||||
u'\u2278': u'\u2279', # [BEST FIT] NEITHER LESS-THAN NOR GREATER-THAN
|
||||
u'\u2279': u'\u2278', # [BEST FIT] NEITHER GREATER-THAN NOR LESS-THAN
|
||||
u'\u227A': u'\u227B', # PRECEDES
|
||||
u'\u227B': u'\u227A', # SUCCEEDS
|
||||
u'\u227C': u'\u227D', # PRECEDES OR EQUAL TO
|
||||
u'\u227D': u'\u227C', # SUCCEEDS OR EQUAL TO
|
||||
u'\u227E': u'\u227F', # [BEST FIT] PRECEDES OR EQUIVALENT TO
|
||||
u'\u227F': u'\u227E', # [BEST FIT] SUCCEEDS OR EQUIVALENT TO
|
||||
u'\u2280': u'\u2281', # [BEST FIT] DOES NOT PRECEDE
|
||||
u'\u2281': u'\u2280', # [BEST FIT] DOES NOT SUCCEED
|
||||
u'\u2282': u'\u2283', # SUBSET OF
|
||||
u'\u2283': u'\u2282', # SUPERSET OF
|
||||
u'\u2284': u'\u2285', # [BEST FIT] NOT A SUBSET OF
|
||||
u'\u2285': u'\u2284', # [BEST FIT] NOT A SUPERSET OF
|
||||
u'\u2286': u'\u2287', # SUBSET OF OR EQUAL TO
|
||||
u'\u2287': u'\u2286', # SUPERSET OF OR EQUAL TO
|
||||
u'\u2288': u'\u2289', # [BEST FIT] NEITHER A SUBSET OF NOR EQUAL TO
|
||||
u'\u2289': u'\u2288', # [BEST FIT] NEITHER A SUPERSET OF NOR EQUAL TO
|
||||
u'\u228A': u'\u228B', # [BEST FIT] SUBSET OF WITH NOT EQUAL TO
|
||||
u'\u228B': u'\u228A', # [BEST FIT] SUPERSET OF WITH NOT EQUAL TO
|
||||
u'\u228F': u'\u2290', # SQUARE IMAGE OF
|
||||
u'\u2290': u'\u228F', # SQUARE ORIGINAL OF
|
||||
u'\u2291': u'\u2292', # SQUARE IMAGE OF OR EQUAL TO
|
||||
u'\u2292': u'\u2291', # SQUARE ORIGINAL OF OR EQUAL TO
|
||||
u'\u2298': u'\u29B8', # CIRCLED DIVISION SLASH
|
||||
u'\u22A2': u'\u22A3', # RIGHT TACK
|
||||
u'\u22A3': u'\u22A2', # LEFT TACK
|
||||
u'\u22A6': u'\u2ADE', # ASSERTION
|
||||
u'\u22A8': u'\u2AE4', # TRUE
|
||||
u'\u22A9': u'\u2AE3', # FORCES
|
||||
u'\u22AB': u'\u2AE5', # DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
|
||||
u'\u22B0': u'\u22B1', # PRECEDES UNDER RELATION
|
||||
u'\u22B1': u'\u22B0', # SUCCEEDS UNDER RELATION
|
||||
u'\u22B2': u'\u22B3', # NORMAL SUBGROUP OF
|
||||
u'\u22B3': u'\u22B2', # CONTAINS AS NORMAL SUBGROUP
|
||||
u'\u22B4': u'\u22B5', # NORMAL SUBGROUP OF OR EQUAL TO
|
||||
u'\u22B5': u'\u22B4', # CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
|
||||
u'\u22B6': u'\u22B7', # ORIGINAL OF
|
||||
u'\u22B7': u'\u22B6', # IMAGE OF
|
||||
u'\u22C9': u'\u22CA', # LEFT NORMAL FACTOR SEMIDIRECT PRODUCT
|
||||
u'\u22CA': u'\u22C9', # RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT
|
||||
u'\u22CB': u'\u22CC', # LEFT SEMIDIRECT PRODUCT
|
||||
u'\u22CC': u'\u22CB', # RIGHT SEMIDIRECT PRODUCT
|
||||
u'\u22CD': u'\u2243', # REVERSED TILDE EQUALS
|
||||
u'\u22D0': u'\u22D1', # DOUBLE SUBSET
|
||||
u'\u22D1': u'\u22D0', # DOUBLE SUPERSET
|
||||
u'\u22D6': u'\u22D7', # LESS-THAN WITH DOT
|
||||
u'\u22D7': u'\u22D6', # GREATER-THAN WITH DOT
|
||||
u'\u22D8': u'\u22D9', # VERY MUCH LESS-THAN
|
||||
u'\u22D9': u'\u22D8', # VERY MUCH GREATER-THAN
|
||||
u'\u22DA': u'\u22DB', # LESS-THAN EQUAL TO OR GREATER-THAN
|
||||
u'\u22DB': u'\u22DA', # GREATER-THAN EQUAL TO OR LESS-THAN
|
||||
u'\u22DC': u'\u22DD', # EQUAL TO OR LESS-THAN
|
||||
u'\u22DD': u'\u22DC', # EQUAL TO OR GREATER-THAN
|
||||
u'\u22DE': u'\u22DF', # EQUAL TO OR PRECEDES
|
||||
u'\u22DF': u'\u22DE', # EQUAL TO OR SUCCEEDS
|
||||
u'\u22E0': u'\u22E1', # [BEST FIT] DOES NOT PRECEDE OR EQUAL
|
||||
u'\u22E1': u'\u22E0', # [BEST FIT] DOES NOT SUCCEED OR EQUAL
|
||||
u'\u22E2': u'\u22E3', # [BEST FIT] NOT SQUARE IMAGE OF OR EQUAL TO
|
||||
u'\u22E3': u'\u22E2', # [BEST FIT] NOT SQUARE ORIGINAL OF OR EQUAL TO
|
||||
u'\u22E4': u'\u22E5', # [BEST FIT] SQUARE IMAGE OF OR NOT EQUAL TO
|
||||
u'\u22E5': u'\u22E4', # [BEST FIT] SQUARE ORIGINAL OF OR NOT EQUAL TO
|
||||
u'\u22E6': u'\u22E7', # [BEST FIT] LESS-THAN BUT NOT EQUIVALENT TO
|
||||
u'\u22E7': u'\u22E6', # [BEST FIT] GREATER-THAN BUT NOT EQUIVALENT TO
|
||||
u'\u22E8': u'\u22E9', # [BEST FIT] PRECEDES BUT NOT EQUIVALENT TO
|
||||
u'\u22E9': u'\u22E8', # [BEST FIT] SUCCEEDS BUT NOT EQUIVALENT TO
|
||||
u'\u22EA': u'\u22EB', # [BEST FIT] NOT NORMAL SUBGROUP OF
|
||||
u'\u22EB': u'\u22EA', # [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP
|
||||
u'\u22EC': u'\u22ED', # [BEST FIT] NOT NORMAL SUBGROUP OF OR EQUAL TO
|
||||
# [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
|
||||
u'\u22ED': u'\u22EC',
|
||||
u'\u22F0': u'\u22F1', # UP RIGHT DIAGONAL ELLIPSIS
|
||||
u'\u22F1': u'\u22F0', # DOWN RIGHT DIAGONAL ELLIPSIS
|
||||
u'\u22F2': u'\u22FA', # ELEMENT OF WITH LONG HORIZONTAL STROKE
|
||||
u'\u22F3': u'\u22FB', # ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
|
||||
u'\u22F4': u'\u22FC', # SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
|
||||
u'\u22F6': u'\u22FD', # ELEMENT OF WITH OVERBAR
|
||||
u'\u22F7': u'\u22FE', # SMALL ELEMENT OF WITH OVERBAR
|
||||
u'\u22FA': u'\u22F2', # CONTAINS WITH LONG HORIZONTAL STROKE
|
||||
u'\u22FB': u'\u22F3', # CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
|
||||
u'\u22FC': u'\u22F4', # SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
|
||||
u'\u22FD': u'\u22F6', # CONTAINS WITH OVERBAR
|
||||
u'\u22FE': u'\u22F7', # SMALL CONTAINS WITH OVERBAR
|
||||
u'\u2308': u'\u2309', # LEFT CEILING
|
||||
u'\u2309': u'\u2308', # RIGHT CEILING
|
||||
u'\u230A': u'\u230B', # LEFT FLOOR
|
||||
u'\u230B': u'\u230A', # RIGHT FLOOR
|
||||
u'\u2329': u'\u232A', # LEFT-POINTING ANGLE BRACKET
|
||||
u'\u232A': u'\u2329', # RIGHT-POINTING ANGLE BRACKET
|
||||
u'\u2768': u'\u2769', # MEDIUM LEFT PARENTHESIS ORNAMENT
|
||||
u'\u2769': u'\u2768', # MEDIUM RIGHT PARENTHESIS ORNAMENT
|
||||
u'\u276A': u'\u276B', # MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
|
||||
u'\u276B': u'\u276A', # MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
|
||||
u'\u276C': u'\u276D', # MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
|
||||
u'\u276D': u'\u276C', # MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
|
||||
u'\u276E': u'\u276F', # HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
|
||||
u'\u276F': u'\u276E', # HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
|
||||
u'\u2770': u'\u2771', # HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
|
||||
u'\u2771': u'\u2770', # HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
|
||||
u'\u2772': u'\u2773', # LIGHT LEFT TORTOISE SHELL BRACKET
|
||||
u'\u2773': u'\u2772', # LIGHT RIGHT TORTOISE SHELL BRACKET
|
||||
u'\u2774': u'\u2775', # MEDIUM LEFT CURLY BRACKET ORNAMENT
|
||||
u'\u2775': u'\u2774', # MEDIUM RIGHT CURLY BRACKET ORNAMENT
|
||||
u'\u27C3': u'\u27C4', # OPEN SUBSET
|
||||
u'\u27C4': u'\u27C3', # OPEN SUPERSET
|
||||
u'\u27C5': u'\u27C6', # LEFT S-SHAPED BAG DELIMITER
|
||||
u'\u27C6': u'\u27C5', # RIGHT S-SHAPED BAG DELIMITER
|
||||
u'\u27C8': u'\u27C9', # REVERSE SOLIDUS PRECEDING SUBSET
|
||||
u'\u27C9': u'\u27C8', # SUPERSET PRECEDING SOLIDUS
|
||||
u'\u27D5': u'\u27D6', # LEFT OUTER JOIN
|
||||
u'\u27D6': u'\u27D5', # RIGHT OUTER JOIN
|
||||
u'\u27DD': u'\u27DE', # LONG RIGHT TACK
|
||||
u'\u27DE': u'\u27DD', # LONG LEFT TACK
|
||||
u'\u27E2': u'\u27E3', # WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK
|
||||
u'\u27E3': u'\u27E2', # WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK
|
||||
u'\u27E4': u'\u27E5', # WHITE SQUARE WITH LEFTWARDS TICK
|
||||
u'\u27E5': u'\u27E4', # WHITE SQUARE WITH RIGHTWARDS TICK
|
||||
u'\u27E6': u'\u27E7', # MATHEMATICAL LEFT WHITE SQUARE BRACKET
|
||||
u'\u27E7': u'\u27E6', # MATHEMATICAL RIGHT WHITE SQUARE BRACKET
|
||||
u'\u27E8': u'\u27E9', # MATHEMATICAL LEFT ANGLE BRACKET
|
||||
u'\u27E9': u'\u27E8', # MATHEMATICAL RIGHT ANGLE BRACKET
|
||||
u'\u27EA': u'\u27EB', # MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
|
||||
u'\u27EB': u'\u27EA', # MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
|
||||
u'\u27EC': u'\u27ED', # MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
|
||||
u'\u27ED': u'\u27EC', # MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
|
||||
u'\u27EE': u'\u27EF', # MATHEMATICAL LEFT FLATTENED PARENTHESIS
|
||||
u'\u27EF': u'\u27EE', # MATHEMATICAL RIGHT FLATTENED PARENTHESIS
|
||||
u'\u2983': u'\u2984', # LEFT WHITE CURLY BRACKET
|
||||
u'\u2984': u'\u2983', # RIGHT WHITE CURLY BRACKET
|
||||
u'\u2985': u'\u2986', # LEFT WHITE PARENTHESIS
|
||||
u'\u2986': u'\u2985', # RIGHT WHITE PARENTHESIS
|
||||
u'\u2987': u'\u2988', # Z NOTATION LEFT IMAGE BRACKET
|
||||
u'\u2988': u'\u2987', # Z NOTATION RIGHT IMAGE BRACKET
|
||||
u'\u2989': u'\u298A', # Z NOTATION LEFT BINDING BRACKET
|
||||
u'\u298A': u'\u2989', # Z NOTATION RIGHT BINDING BRACKET
|
||||
u'\u298B': u'\u298C', # LEFT SQUARE BRACKET WITH UNDERBAR
|
||||
u'\u298C': u'\u298B', # RIGHT SQUARE BRACKET WITH UNDERBAR
|
||||
u'\u298D': u'\u2990', # LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
|
||||
u'\u298E': u'\u298F', # RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
|
||||
u'\u298F': u'\u298E', # LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
|
||||
u'\u2990': u'\u298D', # RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
|
||||
u'\u2991': u'\u2992', # LEFT ANGLE BRACKET WITH DOT
|
||||
u'\u2992': u'\u2991', # RIGHT ANGLE BRACKET WITH DOT
|
||||
u'\u2993': u'\u2994', # LEFT ARC LESS-THAN BRACKET
|
||||
u'\u2994': u'\u2993', # RIGHT ARC GREATER-THAN BRACKET
|
||||
u'\u2995': u'\u2996', # DOUBLE LEFT ARC GREATER-THAN BRACKET
|
||||
u'\u2996': u'\u2995', # DOUBLE RIGHT ARC LESS-THAN BRACKET
|
||||
u'\u2997': u'\u2998', # LEFT BLACK TORTOISE SHELL BRACKET
|
||||
u'\u2998': u'\u2997', # RIGHT BLACK TORTOISE SHELL BRACKET
|
||||
u'\u29B8': u'\u2298', # CIRCLED REVERSE SOLIDUS
|
||||
u'\u29C0': u'\u29C1', # CIRCLED LESS-THAN
|
||||
u'\u29C1': u'\u29C0', # CIRCLED GREATER-THAN
|
||||
u'\u29C4': u'\u29C5', # SQUARED RISING DIAGONAL SLASH
|
||||
u'\u29C5': u'\u29C4', # SQUARED FALLING DIAGONAL SLASH
|
||||
u'\u29CF': u'\u29D0', # LEFT TRIANGLE BESIDE VERTICAL BAR
|
||||
u'\u29D0': u'\u29CF', # VERTICAL BAR BESIDE RIGHT TRIANGLE
|
||||
u'\u29D1': u'\u29D2', # BOWTIE WITH LEFT HALF BLACK
|
||||
u'\u29D2': u'\u29D1', # BOWTIE WITH RIGHT HALF BLACK
|
||||
u'\u29D4': u'\u29D5', # TIMES WITH LEFT HALF BLACK
|
||||
u'\u29D5': u'\u29D4', # TIMES WITH RIGHT HALF BLACK
|
||||
u'\u29D8': u'\u29D9', # LEFT WIGGLY FENCE
|
||||
u'\u29D9': u'\u29D8', # RIGHT WIGGLY FENCE
|
||||
u'\u29DA': u'\u29DB', # LEFT DOUBLE WIGGLY FENCE
|
||||
u'\u29DB': u'\u29DA', # RIGHT DOUBLE WIGGLY FENCE
|
||||
u'\u29F5': u'\u2215', # REVERSE SOLIDUS OPERATOR
|
||||
u'\u29F8': u'\u29F9', # BIG SOLIDUS
|
||||
u'\u29F9': u'\u29F8', # BIG REVERSE SOLIDUS
|
||||
u'\u29FC': u'\u29FD', # LEFT-POINTING CURVED ANGLE BRACKET
|
||||
u'\u29FD': u'\u29FC', # RIGHT-POINTING CURVED ANGLE BRACKET
|
||||
u'\u2A2B': u'\u2A2C', # MINUS SIGN WITH FALLING DOTS
|
||||
u'\u2A2C': u'\u2A2B', # MINUS SIGN WITH RISING DOTS
|
||||
u'\u2A2D': u'\u2A2E', # PLUS SIGN IN LEFT HALF CIRCLE
|
||||
u'\u2A2E': u'\u2A2D', # PLUS SIGN IN RIGHT HALF CIRCLE
|
||||
u'\u2A34': u'\u2A35', # MULTIPLICATION SIGN IN LEFT HALF CIRCLE
|
||||
u'\u2A35': u'\u2A34', # MULTIPLICATION SIGN IN RIGHT HALF CIRCLE
|
||||
u'\u2A3C': u'\u2A3D', # INTERIOR PRODUCT
|
||||
u'\u2A3D': u'\u2A3C', # RIGHTHAND INTERIOR PRODUCT
|
||||
u'\u2A64': u'\u2A65', # Z NOTATION DOMAIN ANTIRESTRICTION
|
||||
u'\u2A65': u'\u2A64', # Z NOTATION RANGE ANTIRESTRICTION
|
||||
u'\u2A79': u'\u2A7A', # LESS-THAN WITH CIRCLE INSIDE
|
||||
u'\u2A7A': u'\u2A79', # GREATER-THAN WITH CIRCLE INSIDE
|
||||
u'\u2A7D': u'\u2A7E', # LESS-THAN OR SLANTED EQUAL TO
|
||||
u'\u2A7E': u'\u2A7D', # GREATER-THAN OR SLANTED EQUAL TO
|
||||
u'\u2A7F': u'\u2A80', # LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
|
||||
u'\u2A80': u'\u2A7F', # GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
|
||||
u'\u2A81': u'\u2A82', # LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
|
||||
u'\u2A82': u'\u2A81', # GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
|
||||
u'\u2A83': u'\u2A84', # LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT
|
||||
u'\u2A84': u'\u2A83', # GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT
|
||||
u'\u2A8B': u'\u2A8C', # LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
|
||||
u'\u2A8C': u'\u2A8B', # GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
|
||||
u'\u2A91': u'\u2A92', # LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL
|
||||
u'\u2A92': u'\u2A91', # GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL
|
||||
# LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL
|
||||
u'\u2A93': u'\u2A94',
|
||||
# GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL
|
||||
u'\u2A94': u'\u2A93',
|
||||
u'\u2A95': u'\u2A96', # SLANTED EQUAL TO OR LESS-THAN
|
||||
u'\u2A96': u'\u2A95', # SLANTED EQUAL TO OR GREATER-THAN
|
||||
u'\u2A97': u'\u2A98', # SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE
|
||||
u'\u2A98': u'\u2A97', # SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE
|
||||
u'\u2A99': u'\u2A9A', # DOUBLE-LINE EQUAL TO OR LESS-THAN
|
||||
u'\u2A9A': u'\u2A99', # DOUBLE-LINE EQUAL TO OR GREATER-THAN
|
||||
u'\u2A9B': u'\u2A9C', # DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN
|
||||
u'\u2A9C': u'\u2A9B', # DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN
|
||||
u'\u2AA1': u'\u2AA2', # DOUBLE NESTED LESS-THAN
|
||||
u'\u2AA2': u'\u2AA1', # DOUBLE NESTED GREATER-THAN
|
||||
u'\u2AA6': u'\u2AA7', # LESS-THAN CLOSED BY CURVE
|
||||
u'\u2AA7': u'\u2AA6', # GREATER-THAN CLOSED BY CURVE
|
||||
u'\u2AA8': u'\u2AA9', # LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
|
||||
u'\u2AA9': u'\u2AA8', # GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
|
||||
u'\u2AAA': u'\u2AAB', # SMALLER THAN
|
||||
u'\u2AAB': u'\u2AAA', # LARGER THAN
|
||||
u'\u2AAC': u'\u2AAD', # SMALLER THAN OR EQUAL TO
|
||||
u'\u2AAD': u'\u2AAC', # LARGER THAN OR EQUAL TO
|
||||
u'\u2AAF': u'\u2AB0', # PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
|
||||
u'\u2AB0': u'\u2AAF', # SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
|
||||
u'\u2AB3': u'\u2AB4', # PRECEDES ABOVE EQUALS SIGN
|
||||
u'\u2AB4': u'\u2AB3', # SUCCEEDS ABOVE EQUALS SIGN
|
||||
u'\u2ABB': u'\u2ABC', # DOUBLE PRECEDES
|
||||
u'\u2ABC': u'\u2ABB', # DOUBLE SUCCEEDS
|
||||
u'\u2ABD': u'\u2ABE', # SUBSET WITH DOT
|
||||
u'\u2ABE': u'\u2ABD', # SUPERSET WITH DOT
|
||||
u'\u2ABF': u'\u2AC0', # SUBSET WITH PLUS SIGN BELOW
|
||||
u'\u2AC0': u'\u2ABF', # SUPERSET WITH PLUS SIGN BELOW
|
||||
u'\u2AC1': u'\u2AC2', # SUBSET WITH MULTIPLICATION SIGN BELOW
|
||||
u'\u2AC2': u'\u2AC1', # SUPERSET WITH MULTIPLICATION SIGN BELOW
|
||||
u'\u2AC3': u'\u2AC4', # SUBSET OF OR EQUAL TO WITH DOT ABOVE
|
||||
u'\u2AC4': u'\u2AC3', # SUPERSET OF OR EQUAL TO WITH DOT ABOVE
|
||||
u'\u2AC5': u'\u2AC6', # SUBSET OF ABOVE EQUALS SIGN
|
||||
u'\u2AC6': u'\u2AC5', # SUPERSET OF ABOVE EQUALS SIGN
|
||||
u'\u2ACD': u'\u2ACE', # SQUARE LEFT OPEN BOX OPERATOR
|
||||
u'\u2ACE': u'\u2ACD', # SQUARE RIGHT OPEN BOX OPERATOR
|
||||
u'\u2ACF': u'\u2AD0', # CLOSED SUBSET
|
||||
u'\u2AD0': u'\u2ACF', # CLOSED SUPERSET
|
||||
u'\u2AD1': u'\u2AD2', # CLOSED SUBSET OR EQUAL TO
|
||||
u'\u2AD2': u'\u2AD1', # CLOSED SUPERSET OR EQUAL TO
|
||||
u'\u2AD3': u'\u2AD4', # SUBSET ABOVE SUPERSET
|
||||
u'\u2AD4': u'\u2AD3', # SUPERSET ABOVE SUBSET
|
||||
u'\u2AD5': u'\u2AD6', # SUBSET ABOVE SUBSET
|
||||
u'\u2AD6': u'\u2AD5', # SUPERSET ABOVE SUPERSET
|
||||
u'\u2ADE': u'\u22A6', # SHORT LEFT TACK
|
||||
u'\u2AE3': u'\u22A9', # DOUBLE VERTICAL BAR LEFT TURNSTILE
|
||||
u'\u2AE4': u'\u22A8', # VERTICAL BAR DOUBLE LEFT TURNSTILE
|
||||
u'\u2AE5': u'\u22AB', # DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE
|
||||
u'\u2AEC': u'\u2AED', # DOUBLE STROKE NOT SIGN
|
||||
u'\u2AED': u'\u2AEC', # REVERSED DOUBLE STROKE NOT SIGN
|
||||
u'\u2AF7': u'\u2AF8', # TRIPLE NESTED LESS-THAN
|
||||
u'\u2AF8': u'\u2AF7', # TRIPLE NESTED GREATER-THAN
|
||||
u'\u2AF9': u'\u2AFA', # DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO
|
||||
u'\u2AFA': u'\u2AF9', # DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO
|
||||
u'\u2E02': u'\u2E03', # LEFT SUBSTITUTION BRACKET
|
||||
u'\u2E03': u'\u2E02', # RIGHT SUBSTITUTION BRACKET
|
||||
u'\u2E04': u'\u2E05', # LEFT DOTTED SUBSTITUTION BRACKET
|
||||
u'\u2E05': u'\u2E04', # RIGHT DOTTED SUBSTITUTION BRACKET
|
||||
u'\u2E09': u'\u2E0A', # LEFT TRANSPOSITION BRACKET
|
||||
u'\u2E0A': u'\u2E09', # RIGHT TRANSPOSITION BRACKET
|
||||
u'\u2E0C': u'\u2E0D', # LEFT RAISED OMISSION BRACKET
|
||||
u'\u2E0D': u'\u2E0C', # RIGHT RAISED OMISSION BRACKET
|
||||
u'\u2E1C': u'\u2E1D', # LEFT LOW PARAPHRASE BRACKET
|
||||
u'\u2E1D': u'\u2E1C', # RIGHT LOW PARAPHRASE BRACKET
|
||||
u'\u2E20': u'\u2E21', # LEFT VERTICAL BAR WITH QUILL
|
||||
u'\u2E21': u'\u2E20', # RIGHT VERTICAL BAR WITH QUILL
|
||||
u'\u2E22': u'\u2E23', # TOP LEFT HALF BRACKET
|
||||
u'\u2E23': u'\u2E22', # TOP RIGHT HALF BRACKET
|
||||
u'\u2E24': u'\u2E25', # BOTTOM LEFT HALF BRACKET
|
||||
u'\u2E25': u'\u2E24', # BOTTOM RIGHT HALF BRACKET
|
||||
u'\u2E26': u'\u2E27', # LEFT SIDEWAYS U BRACKET
|
||||
u'\u2E27': u'\u2E26', # RIGHT SIDEWAYS U BRACKET
|
||||
u'\u2E28': u'\u2E29', # LEFT DOUBLE PARENTHESIS
|
||||
u'\u2E29': u'\u2E28', # RIGHT DOUBLE PARENTHESIS
|
||||
u'\u3008': u'\u3009', # LEFT ANGLE BRACKET
|
||||
u'\u3009': u'\u3008', # RIGHT ANGLE BRACKET
|
||||
u'\u300A': u'\u300B', # LEFT DOUBLE ANGLE BRACKET
|
||||
u'\u300B': u'\u300A', # RIGHT DOUBLE ANGLE BRACKET
|
||||
u'\u300C': u'\u300D', # [BEST FIT] LEFT CORNER BRACKET
|
||||
u'\u300D': u'\u300C', # [BEST FIT] RIGHT CORNER BRACKET
|
||||
u'\u300E': u'\u300F', # [BEST FIT] LEFT WHITE CORNER BRACKET
|
||||
u'\u300F': u'\u300E', # [BEST FIT] RIGHT WHITE CORNER BRACKET
|
||||
u'\u3010': u'\u3011', # LEFT BLACK LENTICULAR BRACKET
|
||||
u'\u3011': u'\u3010', # RIGHT BLACK LENTICULAR BRACKET
|
||||
u'\u3014': u'\u3015', # LEFT TORTOISE SHELL BRACKET
|
||||
u'\u3015': u'\u3014', # RIGHT TORTOISE SHELL BRACKET
|
||||
u'\u3016': u'\u3017', # LEFT WHITE LENTICULAR BRACKET
|
||||
u'\u3017': u'\u3016', # RIGHT WHITE LENTICULAR BRACKET
|
||||
u'\u3018': u'\u3019', # LEFT WHITE TORTOISE SHELL BRACKET
|
||||
u'\u3019': u'\u3018', # RIGHT WHITE TORTOISE SHELL BRACKET
|
||||
u'\u301A': u'\u301B', # LEFT WHITE SQUARE BRACKET
|
||||
u'\u301B': u'\u301A', # RIGHT WHITE SQUARE BRACKET
|
||||
u'\uFE59': u'\uFE5A', # SMALL LEFT PARENTHESIS
|
||||
u'\uFE5A': u'\uFE59', # SMALL RIGHT PARENTHESIS
|
||||
u'\uFE5B': u'\uFE5C', # SMALL LEFT CURLY BRACKET
|
||||
u'\uFE5C': u'\uFE5B', # SMALL RIGHT CURLY BRACKET
|
||||
u'\uFE5D': u'\uFE5E', # SMALL LEFT TORTOISE SHELL BRACKET
|
||||
u'\uFE5E': u'\uFE5D', # SMALL RIGHT TORTOISE SHELL BRACKET
|
||||
u'\uFE64': u'\uFE65', # SMALL LESS-THAN SIGN
|
||||
u'\uFE65': u'\uFE64', # SMALL GREATER-THAN SIGN
|
||||
u'\uFF08': u'\uFF09', # FULLWIDTH LEFT PARENTHESIS
|
||||
u'\uFF09': u'\uFF08', # FULLWIDTH RIGHT PARENTHESIS
|
||||
u'\uFF1C': u'\uFF1E', # FULLWIDTH LESS-THAN SIGN
|
||||
u'\uFF1E': u'\uFF1C', # FULLWIDTH GREATER-THAN SIGN
|
||||
u'\uFF3B': u'\uFF3D', # FULLWIDTH LEFT SQUARE BRACKET
|
||||
u'\uFF3D': u'\uFF3B', # FULLWIDTH RIGHT SQUARE BRACKET
|
||||
u'\uFF5B': u'\uFF5D', # FULLWIDTH LEFT CURLY BRACKET
|
||||
u'\uFF5D': u'\uFF5B', # FULLWIDTH RIGHT CURLY BRACKET
|
||||
u'\uFF5F': u'\uFF60', # FULLWIDTH LEFT WHITE PARENTHESIS
|
||||
u'\uFF60': u'\uFF5F', # FULLWIDTH RIGHT WHITE PARENTHESIS
|
||||
u'\uFF62': u'\uFF63', # [BEST FIT] HALFWIDTH LEFT CORNER BRACKET
|
||||
u'\uFF63': u'\uFF62', # [BEST FIT] HALFWIDTH RIGHT CORNER BRACKET
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,251 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="custom_external_layout_standard_barcode">
|
||||
<div class="header">
|
||||
<div class="row">
|
||||
<br/>
|
||||
<table align="left"
|
||||
style="border:1px solid white;width:50;margin-left:60px;margin-top:0px;margin-right:5px;margin-bottom:40px;text-align: justify;">
|
||||
<tr style="border:0px">
|
||||
<td style="font-weight: bold;border:0px;padding-right:30px !important;">Number:
|
||||
<t t-esc="o.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="border:0px">
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold;font-stretch: expanded;">
|
||||
Date:
|
||||
</span>
|
||||
|
||||
<t t-set="date_hijri" t-value="o.transaction_date_hijri"/>
|
||||
|
||||
<t t-set="date_hijri2" t-value="date_hijri.split('-')"/>
|
||||
|
||||
<t t-esc="date_hijri2[0]"/>/<t t-esc="date_hijri2[1]"/>/
|
||||
<t t-esc="date_hijri2[2]"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold;">Reference:</span>
|
||||
<span t-field="o.transaction_date" t-field-options='{"format": "yyyy/MM/dd"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold">Attachment:</span>
|
||||
<span style="direction: ltr !important;">
|
||||
<t t-esc="o.attachment_num"/>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="border:0px">
|
||||
<td colspan="2" style="border:0px">
|
||||
<img t-att-src="'/report/barcode/?type=%s&value=%s&width=%s&height=%s' % ('Code128', o.name, 600, 100)"
|
||||
style="width:250px;height:40px;margin-top:5px;"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="article o_report_layout_standard">
|
||||
<t t-raw="0"/>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- <div class="text-center">-->
|
||||
<!-- <div class="text-muted">-->
|
||||
<!-- Page: <span class="page"/> / <span class="topage"/>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="barcode_external_layout">
|
||||
<!-- Multicompany -->
|
||||
<t t-if="not o and doc">
|
||||
<t t-set="o" t-value="doc"/>
|
||||
</t>
|
||||
|
||||
<t t-if="o and 'company_id' in o">
|
||||
<t t-set="company" t-value="o.company_id.sudo()"/>
|
||||
</t>
|
||||
<t t-if="not o or not 'company_id' in o">
|
||||
<t t-set="company" t-value="res_company"/>
|
||||
</t>
|
||||
<div class="header">
|
||||
<div class="row">
|
||||
<br/>
|
||||
<table align="left"
|
||||
style="border:1px solid white;width:50;margin-left:60px;margin-top:0px;margin-right:5px;margin-bottom:40px;text-align: justify;">
|
||||
<tr style="border:0px">
|
||||
<td style="font-weight: bold;border:0px;padding-right:30px !important;">Number:
|
||||
<t t-esc="o.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="border:0px">
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold;font-stretch: expanded;">
|
||||
Date:
|
||||
</span>
|
||||
|
||||
<t t-set="date_hijri" t-value="o.transaction_date_hijri"/>
|
||||
|
||||
<t t-set="date_hijri2" t-value="date_hijri.split('-')"/>
|
||||
|
||||
<t t-esc="date_hijri2[0]"/>/<t t-esc="date_hijri2[1]"/>/
|
||||
<t t-esc="date_hijri2[2]"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold;">Reference:</span>
|
||||
<span t-field="o.transaction_date" t-field-options='{"format": "yyyy/MM/dd"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold">Attachment:</span>
|
||||
<span style="direction: ltr !important;">
|
||||
<t t-esc="o.attachment_num"/>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="border:0px">
|
||||
<td colspan="2" style="border:0px">
|
||||
<img t-att-src="'/report/barcode/?type=%s&value=%s&width=%s&height=%s' % ('Code128', o.name, 600, 100)"
|
||||
style="width:250px;height:40px;margin-top:5px;"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br></br>
|
||||
<!-- <t t-if="company.external_report_layout == 'background'">-->
|
||||
<!-- <t t-call="cm_odex_barcode.custom_external_layout_standard_barcode"><t t-raw="0"/></t>-->
|
||||
<!-- </t>-->
|
||||
<!-- <t t-if="company.external_report_layout == 'boxed'">-->
|
||||
<!-- <t t-call="cm_odex_barcode.custom_external_layout_standard_barcode"><t t-raw="0"/></t>-->
|
||||
<!-- </t>-->
|
||||
<!-- <t t-if="company.external_report_layout == 'clean'">-->
|
||||
<!-- <t t-call="cm_odex_barcode.custom_external_layout_standard_barcode"><t t-raw="0"/></t>-->
|
||||
<!-- </t>-->
|
||||
<!-- <t t-if="company.external_report_layout in (False, 'standard')">-->
|
||||
<!-- <t t-call="cm_odex_barcode.custom_external_layout_standard_barcode"><t t-raw="0"/></t>-->
|
||||
<!-- </t>-->
|
||||
</template>
|
||||
<!-- Translatable template -->
|
||||
<template id="report_transaction_barcode">
|
||||
<t t-call="cm_odex_barcode.barcode_external_layout">
|
||||
<div class="page">
|
||||
<div class="row text-center" style="direction: rtl;">
|
||||
<table style="margin-right:70%;">
|
||||
<tr>
|
||||
<td style="font-weight: bold;">Number:</td>
|
||||
<td style="direction: ltr !important;">
|
||||
<t t-esc="o.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table style="margin-right:70%;">
|
||||
<tr>
|
||||
<td><span style="font-weight:bold">Date:</span>
|
||||
|
||||
<t t-set="date_hijri" t-value="o.transaction_date_hijri"/>
|
||||
|
||||
<t t-set="date_hijri2" t-value="date_hijri.split('-')"/>
|
||||
|
||||
<t t-esc="date_hijri2[0]"/>/<t t-esc="date_hijri2[1]"/>/<t t-esc="date_hijri2[2]"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span style="font-weight:bold">Reference:</span>
|
||||
<span t-field="o.transaction_date" t-field-options='{"format": "yyyy/MM/dd"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-weight:bold">Attachment:</span>
|
||||
<span style="direction: ltr !important;">
|
||||
<t t-esc="o.attachment_num"/>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<img t-att-src="'/report/barcode/?type=%s&value=%s&width=%s&height=%s' % ('Code128', o.name, 600, 100)"
|
||||
style="width:250px;height:40px;margin-top:5px;"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_internal_transaction_barcode">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="cm_odex_barcode.report_transaction_barcode"/>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_incoming_transaction_barcode">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="cm_odex_barcode.report_transaction_barcode"/>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_outgoing_transaction_barcode">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-call="cm_odex_barcode.report_transaction_barcode"/>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<record id="paperformat_transactions" model="report.paperformat">
|
||||
<field name="name">European A4 Transactions</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="format">A4</field>
|
||||
<field name="orientation">Portrait</field>
|
||||
<field name="margin_top">5</field>
|
||||
<field name="margin_bottom">28</field>
|
||||
<field name="margin_left">7</field>
|
||||
<field name="margin_right">7</field>
|
||||
<field name="header_line" eval="False"/>
|
||||
<field name="header_spacing">35</field>
|
||||
<field name="dpi">90</field>
|
||||
</record>
|
||||
|
||||
<record id="act_transaction_out_barcode" model="ir.actions.report">
|
||||
<field name="name">Outgoing Transaction Barcode</field>
|
||||
<field name="model">outgoing.transaction</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">cm_odex_barcode.report_outgoing_transaction_barcode</field>
|
||||
<field name="attachment_use" eval="False"/>
|
||||
<field name="paperformat_id" ref="paperformat_transactions"/>
|
||||
</record>
|
||||
|
||||
<record id="act_transaction_in_barcode" model="ir.actions.report">
|
||||
<field name="name">Incoming Transaction Barcode</field>
|
||||
<field name="model">incoming.transaction</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">cm_odex_barcode.report_incoming_transaction_barcode</field>
|
||||
<field name="attachment_use" eval="False"/>
|
||||
<field name="paperformat_id" ref="paperformat_transactions"/>
|
||||
</record>
|
||||
|
||||
<record id="act_transaction_internal_barcode" model="ir.actions.report">
|
||||
<field name="name">Internal Transaction Barcode</field>
|
||||
<field name="model">internal.transaction</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">cm_odex_barcode.report_internal_transaction_barcode</field>
|
||||
<field name="attachment_use" eval="False"/>
|
||||
<field name="paperformat_id" ref="paperformat_transactions"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="extend_tran_header" inherit_id="exp_transaction_documents.custom_external_layout_standard_tran">
|
||||
<xpath expr="//div[@class='header']" position="replace">
|
||||
<div class="header">
|
||||
<div class="row">
|
||||
<br/>
|
||||
<table align="left"
|
||||
style="border:1px solid white;width:50;margin-left:60px;margin-top:0px;margin-right:5px;margin-bottom:40px;text-align: justify;">
|
||||
<tr style="border:0px">
|
||||
<td style="font-weight: bold;border:0px;padding-right:30px !important;">Number:
|
||||
<t t-esc="o.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="border:0px">
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold;font-stretch: expanded;">
|
||||
Date:
|
||||
</span>
|
||||
|
||||
<t t-set="date_hijri" t-value="o.transaction_date_hijri"/>
|
||||
|
||||
<t t-set="date_hijri2" t-value="date_hijri.split('-')"/>
|
||||
|
||||
<t t-esc="date_hijri2[0]"/>/<t t-esc="date_hijri2[1]"/>/
|
||||
<t t-esc="date_hijri2[2]"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold;">Reference:</span>
|
||||
<span t-field="o.transaction_date" t-field-options='{"format": "yyyy/MM/dd"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" style="border:0px;padding-right:30px !important;">
|
||||
<span style="font-weight:bold">Attachment:</span>
|
||||
<span style="direction: ltr !important;">
|
||||
<t t-esc="o.attachment_num"/>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="border:0px">
|
||||
<td colspan="2" style="border:0px">
|
||||
<img t-att-src="'/report/barcode/?type=%s&value=%s&width=%s&height=%s' % ('Code128', o.name, 600, 100)"
|
||||
style="width:250px;height:40px;margin-top:5px;"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br></br>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
odoo.cm_odex_barcode = function (instance) {
|
||||
'use strict';
|
||||
var _t = instance.web._t,
|
||||
_lt = instance.web._lt;
|
||||
var QWeb = instance.web.qweb;
|
||||
console.log(">>>>>>>>>>>>>>>>>>>>>>>",QWeb)
|
||||
instance.web.form.FieldBinaryImage.include({
|
||||
render_value: function () {
|
||||
var self = this;
|
||||
var url;
|
||||
if (this.get('value') && !instance.web.form.is_bin_size(this.get('value'))) {
|
||||
url = 'data:image/png;base64,' + this.get('value');
|
||||
} else if (this.get('value')) {
|
||||
var id = JSON.stringify(this.view.datarecord.id || null);
|
||||
var field = this.name;
|
||||
if (this.options.preview_image)
|
||||
field = this.options.preview_image;
|
||||
url = this.session.url('/web/binary/image', {
|
||||
model: this.view.dataset.model,
|
||||
id: id,
|
||||
field: field,
|
||||
t: (new Date().getTime()),
|
||||
});
|
||||
} else {
|
||||
url = this.placeholder;
|
||||
}
|
||||
var $img = $(QWeb.render("FieldBinaryImage-img", {widget: this, url: url}));
|
||||
$($img).click(function (e) {
|
||||
if (self.view.get("actual_mode") == "view") {
|
||||
var $button = $(".oe_form_button_edit");
|
||||
console.log($img[0].src)
|
||||
window.location.href=$img[0].src
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
this.$el.find('> img').remove();
|
||||
this.$el.prepend($img);
|
||||
$img.load(function () {
|
||||
if (!self.options.size)
|
||||
return;
|
||||
$img.css("max-width", "" + self.options.size[0] + "px");
|
||||
$img.css("max-height", "" + self.options.size[1] + "px");
|
||||
});
|
||||
$img.on('error', function () {
|
||||
self.on_clear();
|
||||
$img.attr('src', self.placeholder);
|
||||
instance.webclient.notification.warn(_t("Image"), _t("Could not display the selected image."));
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2016 Flavio Corpa <flavio.corpa@tecnativa.com>
|
||||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
|
||||
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||
<xpath expr=".">
|
||||
<script type="text/javascript"
|
||||
src="/cm_odex_barcode/static/src/js/cm_odex_barcode.js"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="form_internal_barcode_print_button" model="ir.ui.view">
|
||||
<field name="name">print internal barcode</field>
|
||||
<field name="model">internal.transaction</field>
|
||||
<field name="inherit_id" ref="exp_transaction_documents.internal_transaction_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- <xpath expr="//header" position="inside">-->
|
||||
<!-- <button type="action" name="%(act_transaction_internal_barcode)d" string="Print Barcode" class="oe_highlight"/>-->
|
||||
<!-- </xpath>-->
|
||||
<field name="type" position="after">
|
||||
<field name="create_uid" invisible="1"/>
|
||||
</field>
|
||||
<xpath expr="/form/sheet/notebook/page[3]" position="after">
|
||||
<page string="Review Barcode">
|
||||
<group>
|
||||
<field name="binary_barcode" widget="image"/>
|
||||
</group>
|
||||
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!---->
|
||||
<record id="form_outgoing_barcode_print_button" model="ir.ui.view">
|
||||
<field name="name">print barcode</field>
|
||||
<field name="model">outgoing.transaction</field>
|
||||
<field name="inherit_id" ref="exp_transaction_documents.outgoing_external_transaction_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button type="action" name="%(act_transaction_out_barcode)d" string="Print Barcode" class="oe_highlight"/>
|
||||
</xpath>
|
||||
<field name="type" position="after">
|
||||
<field name="create_uid" invisible="1"/>
|
||||
</field>
|
||||
<xpath expr="/form/sheet/notebook/page[3]" position="after">
|
||||
<page string="Review Barcode">
|
||||
<group>
|
||||
<field name="binary_barcode" widget="image"/>
|
||||
</group>
|
||||
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!---->
|
||||
<record id="form_incoming_barcode_print_button" model="ir.ui.view">
|
||||
<field name="name">print incoming barcode</field>
|
||||
<field name="model">incoming.transaction</field>
|
||||
<field name="inherit_id" ref="exp_transaction_documents.incoming_external_transaction_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- <xpath expr="//header" position="inside">-->
|
||||
<!-- <button type="action" name="%(act_transaction_in_barcode)d" string="Print Barcode" class="oe_highlight"/>-->
|
||||
<!-- </xpath>-->
|
||||
<field name="type" position="after">
|
||||
<field name="create_uid" invisible="1"/>
|
||||
</field>
|
||||
<xpath expr="/form/sheet/notebook/page[3]" position="after">
|
||||
<page string="Review Barcode">
|
||||
<group>
|
||||
<field name="binary_barcode" widget="image"/>
|
||||
</group>
|
||||
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from . import models
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odex - Communications Management System.
|
||||
# Copyright (C) 2017 Expert Co. Ltd. (<http://exp-sa.com>).
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'Correspondence Traking (Mailing)',
|
||||
'version': '0.1',
|
||||
'sequence': 20,
|
||||
'author': 'Expert Co. Ltd.',
|
||||
'category': 'Odex25-Transactions/Odex25-Transactions',
|
||||
'summary': 'Mailing <> Correspondence Traking',
|
||||
'description': """
|
||||
Odex - Communications Management System - Link with Email
|
||||
==========================================================
|
||||
|
||||
* Import Transactions from email.
|
||||
""",
|
||||
'website': 'http://www.exp-sa.com',
|
||||
'depends': ['base', 'base_odex', 'mail','exp_transaction_documents'],
|
||||
'data': [
|
||||
'views/actions_and_menus.xml',
|
||||
],
|
||||
'qweb': [
|
||||
],
|
||||
'external_dependencies': {},
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': False,
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * exp_cm_mail_odex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 11.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-09-22 13:13+0000\n"
|
||||
"PO-Revision-Date: 2019-09-22 13:13+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.model.fields,help:exp_cm_mail_odex.field_cm_subject_type_default_value_email
|
||||
#: model:ir.model.fields,help:exp_cm_mail_odex.field_cm_transaction_important_default_value_email
|
||||
msgid "Check if you will used in email."
|
||||
msgstr "حدد إذا كانت القيمه الافتراضية المستخدمه في معاملات البريد الالكتروني"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.actions.act_window,help:exp_cm_mail_odex.cm_transaction_internal_in_mail__list_action
|
||||
msgid "Create the first Internal Transaction"
|
||||
msgstr "إنشاء معامله داخلية جديده"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.model.fields,field_description:exp_cm_mail_odex.field_cm_subject_type_default_value_email
|
||||
#: model:ir.model.fields,field_description:exp_cm_mail_odex.field_cm_transaction_important_default_value_email
|
||||
msgid "Default value in email"
|
||||
msgstr "القيمة الافتراضية للبريد الالكتروني"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: code:addons/exp_cm_mail_odex/models/extend_transaction.py:11
|
||||
#: selection:incoming.transaction,source:0
|
||||
#: selection:internal.transaction,source:0
|
||||
#: selection:outgoing.transaction,source:0
|
||||
#: selection:transaction.transaction,source:0
|
||||
#, python-format
|
||||
msgid "Email"
|
||||
msgstr "البريد الالكتروني"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.actions.act_window,name:exp_cm_mail_odex.cm_transaction_internal_in_mail__list_action
|
||||
#: model:ir.ui.menu,name:exp_cm_mail_odex.cm_transaction_internal_in_menu
|
||||
msgid "Email Internal Transactions"
|
||||
msgstr "معاملات البريد الالكتروني"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: code:addons/exp_cm_mail_odex/models/extend_transaction.py:10
|
||||
#: selection:incoming.transaction,source:0
|
||||
#: selection:internal.transaction,source:0
|
||||
#: selection:outgoing.transaction,source:0
|
||||
#: selection:transaction.transaction,source:0
|
||||
#, python-format
|
||||
msgid "Manual"
|
||||
msgstr "يدوي"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: code:addons/exp_cm_mail_odex/models/extend_transaction.py:12
|
||||
#: selection:incoming.transaction,source:0
|
||||
#: selection:internal.transaction,source:0
|
||||
#: selection:outgoing.transaction,source:0
|
||||
#: selection:transaction.transaction,source:0
|
||||
#, python-format
|
||||
msgid "System"
|
||||
msgstr "تلقائي"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.model.fields,field_description:exp_cm_mail_odex.field_incoming_transaction_source
|
||||
#: model:ir.model.fields,field_description:exp_cm_mail_odex.field_internal_transaction_source
|
||||
#: model:ir.model.fields,field_description:exp_cm_mail_odex.field_outgoing_transaction_source
|
||||
#: model:ir.model.fields,field_description:exp_cm_mail_odex.field_transaction_transaction_source
|
||||
msgid "Transaction Source"
|
||||
msgstr "مصدر المعامله"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.model,name:exp_cm_mail_odex.model_cm_subject_type
|
||||
msgid "cm.subject.type"
|
||||
msgstr "cm.subject.type"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.model,name:exp_cm_mail_odex.model_cm_transaction_important
|
||||
msgid "cm.transaction.important"
|
||||
msgstr "cm.transaction.important"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.model,name:exp_cm_mail_odex.model_transaction_transaction
|
||||
msgid "for common attribute between transaction"
|
||||
msgstr "for common attribute between transaction"
|
||||
|
||||
#. module: exp_cm_mail_odex
|
||||
#: model:ir.model,name:exp_cm_mail_odex.model_internal_transaction
|
||||
msgid "internal Transaction"
|
||||
msgstr "المعاملات الداخلية"
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from . import extend_related
|
||||
from . import extend_transaction
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class SubjectType(models.Model):
|
||||
_inherit = 'cm.subject.type'
|
||||
|
||||
default_value_email = fields.Boolean(string='Default value in email', help='Check if you will used in email.', default=False)
|
||||
|
||||
|
||||
class ImportantDegree(models.Model):
|
||||
_inherit = 'cm.transaction.important'
|
||||
|
||||
default_value_email = fields.Boolean(string='Default value in email', help='Check if you will used in email.', default=False)
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
from odoo import api, models, fields,_
|
||||
from email import utils
|
||||
|
||||
|
||||
class Transaction(models.Model):
|
||||
_inherit = 'transaction.transaction'
|
||||
|
||||
source = fields.Selection(string='Transaction Source', selection=[
|
||||
('manual', _('Manual')),
|
||||
('email', _('Email')),
|
||||
('auto', _('System')),
|
||||
], default='manual')
|
||||
|
||||
@api.returns('cm.entity')
|
||||
def get_entity_by_email(self, emailaddr):
|
||||
"""
|
||||
return cm.entity using email address
|
||||
|
||||
:param emailaddr: entity email
|
||||
|
||||
:return: cm.entity: object
|
||||
"""
|
||||
Entity = self.env['cm.entity']
|
||||
Partner = self.env['res.partner']
|
||||
User = self.env['res.users']
|
||||
email = utils.parseaddr(emailaddr)[1]
|
||||
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>email",email)
|
||||
partners = Partner.search([('email', '=ilike', email)])
|
||||
# return first entity in this range
|
||||
if not len(partners):
|
||||
return Entity # empty entity
|
||||
users = User.search([('partner_id', 'in', partners.ids)])
|
||||
entities = Entity.search([('partner_id', 'in', partners.ids)])
|
||||
if not len(entities) and len(users):
|
||||
entities = Entity.search([('user_id', 'in', users.ids)])
|
||||
return len(entities) and entities[0] or Entity
|
||||
|
||||
|
||||
class IncomingTransaction(models.Model):
|
||||
_inherit = 'internal.transaction'
|
||||
|
||||
@api.model
|
||||
def message_new(self, msg_dict, custom_values=None):
|
||||
"""
|
||||
Overrides mail_thread message_new that is called by the mailgateway through message_process.
|
||||
This override updates the document according to the email.
|
||||
|
||||
:param msg_dict: a map containing the email details and
|
||||
attachments. See ``message_process`` and
|
||||
``mail.message.parse`` for details.
|
||||
|
||||
:param custom_values: optional dictionary of additional
|
||||
field values to pass to create()
|
||||
when creating the new thread record.
|
||||
Be careful, these values may override
|
||||
any other values coming from the message.
|
||||
|
||||
:return: the id of the newly created thread object
|
||||
"""
|
||||
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>hello iam custom")
|
||||
context = self.env.context
|
||||
data = {}
|
||||
if isinstance(custom_values, dict):
|
||||
data = custom_values.copy()
|
||||
model = context.get('thread_model') or self._name
|
||||
model_pool = self.env[model]
|
||||
fields = model_pool.with_context(**context).fields_get()
|
||||
if 'subject' in fields and not data.get('name'):
|
||||
data['subject'] = msg_dict.get('subject', '')
|
||||
if 'body' in fields and not data.get('name'):
|
||||
data['body'] = msg_dict.get('body', '')
|
||||
email_from = msg_dict.get('email_from', '')
|
||||
if email_from:
|
||||
entity = self.get_entity_by_email(email_from)
|
||||
if len(entity):
|
||||
# data['to_ids'] = [(4, entity.id)]
|
||||
data['employee_id'] = entity.id
|
||||
data['state'] = 'draft'
|
||||
data['source'] = 'email'
|
||||
res_id = model_pool.with_context(**context).create(data)
|
||||
res_id.fetch_sequence(data={}, now=True)
|
||||
return res_id.id
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<odoo>
|
||||
<data>
|
||||
|
||||
<record model="ir.actions.act_window" id="cm_transaction_internal_in_mail__list_action">
|
||||
<field name="name">Email Internal Transactions</field>
|
||||
<field name="res_model">internal.transaction</field>
|
||||
<field name="domain">[('source','=','email'),('employee_id.user_id', '=', uid),('state', 'not in', ['closed'])]</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">Create the first Internal Transaction
|
||||
</p>
|
||||
</field>
|
||||
<field name="search_view_id" ref="exp_transaction_documents.view_internal_transaction_filter"/>
|
||||
<field name="context">{'search_default_favorite': 1,'search_default_unread': 1}</field>
|
||||
</record>
|
||||
|
||||
<menuitem sequence="8" id="cm_transaction_internal_in_menu" name="Email Internal Transactions"
|
||||
parent="exp_transaction_documents.parent_internal_tran_menu" action="cm_transaction_internal_in_mail__list_action"/>
|
||||
|
||||
<record id="cm_subject_type_inherit_form" model="ir.ui.view">
|
||||
<field name="name">cm.subject.type.form</field>
|
||||
<field name="model">cm.subject.type</field>
|
||||
<field name="inherit_id" ref="exp_transaction_documents.cm_subject_type_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="after">
|
||||
<field name="default_value_email"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
from . import controllers
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odex - Communications Management System.
|
||||
# Copyright (C) 2019 Expert Co. Ltd. (<http://exp-sa.com>).
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'Late Mail Reminder',
|
||||
'version': '1.0',
|
||||
'sequence': 10,
|
||||
'author': "Expert Co. Ltd. - Sudan team",
|
||||
'category': 'Odex25-Transactions/Odex25-Transactions',
|
||||
'summary': 'mail reminder',
|
||||
'description': """
|
||||
Late Mail Reminder
|
||||
========================================
|
||||
extend for stander landed costs to change work flow and to add new field""",
|
||||
'website': 'http://www.exp-sa.com',
|
||||
'depends': ['fetchmail'],
|
||||
'data': [
|
||||
'data/late_email_data.xml',
|
||||
'data/mail_data.xml',
|
||||
'views/late_mail_reminder_views.xml',
|
||||
'views/assets.xml',
|
||||
|
||||
],
|
||||
'qweb' : [
|
||||
# 'static/src/xml/notification_dialog.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': True,
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
from . import main
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo import SUPERUSER_ID
|
||||
|
||||
|
||||
class ReminderPopupAlert(http.Controller):
|
||||
|
||||
@http.route('/reminder/notifications', type='json', auth="user")
|
||||
def load_messages_alert(self, **kw):
|
||||
cr, uid = request.cr, SUPERUSER_ID
|
||||
cr.execute(
|
||||
"""select mail_message_id from mail_message_res_partner_needaction_rel where res_partner_id = """ + str(
|
||||
request.env.user.partner_id.id))
|
||||
Messages_ids = []
|
||||
for line in cr.fetchall():
|
||||
s = request.env['mail.message'].browse(line[0])
|
||||
for li in s:
|
||||
for x in li.notification_ids:
|
||||
if x.res_partner_id.id == request.env.user.partner_id.id and x.is_read == False:
|
||||
Messages_ids.append(line[0])
|
||||
list_item = []
|
||||
Messages = http.request.env['mail.message'].search([('id', 'in', Messages_ids)], order='date asc')
|
||||
base_url = http.request.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
for message in Messages:
|
||||
action_id = ''
|
||||
if message.model:
|
||||
reminder_line_ids = http.request.env['late.email.reminder.line'].sudo().search(
|
||||
[('model_id', '=', message.model)])
|
||||
# for reminder_line_id in reminder_line_ids:
|
||||
# for group in reminder_line_id.group_ids:
|
||||
# if request.env.user.id in group.users.ids:
|
||||
# # if reminder_line_id.menu_id.action:
|
||||
# action_id = reminder_line_id.menu_id.action.id
|
||||
item = {
|
||||
'subject': message.body,
|
||||
'id': message.id,
|
||||
'res_id': message.res_id,
|
||||
'res_model': message.model,
|
||||
'base_url': base_url,
|
||||
# 'action_id' : action_id,
|
||||
}
|
||||
list_item.append(item)
|
||||
return list_item
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- late email -->
|
||||
<record id="exp_late_email_reminder" model="late.email.reminder">
|
||||
<field name="number_of_days">5</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record model="ir.cron" id="late_reminder_mail">
|
||||
<field name="name">Late Email Reminder</field>
|
||||
<field name="active">True</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model_id" ref="model_late_email_reminder" />
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.action_send_late_email()</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import late_mail_remainder
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from datetime import date, datetime, timedelta
|
||||
import logging
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATE_FORMAT
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DATE
|
||||
from odoo import models, fields, api, _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LateEmailReminder(models.Model):
|
||||
_name = 'late.email.reminder'
|
||||
_order = 'create_date desc'
|
||||
|
||||
number_of_days = fields.Integer(string='Number Of Days')
|
||||
line_ids = fields.One2many('late.email.reminder.line', 'late_email_id', string='Lines')
|
||||
|
||||
|
||||
def execute(self):
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'reload',
|
||||
}
|
||||
|
||||
|
||||
def send_message(self, template=None, rec=None, model_name='', email='', partner_ids=[]):
|
||||
if not template:
|
||||
return
|
||||
if not template:
|
||||
return
|
||||
template.write({'email_to': email,
|
||||
})
|
||||
mail_id = template.with_context(lang=self.env.user.lang).send_mail(
|
||||
rec.id, force_send=True, raise_exception=False)
|
||||
email = self.env['mail.mail'].browse(mail_id)
|
||||
if email:
|
||||
email.mail_message_id.partner_ids = [(6, 0, partner_ids)]
|
||||
email.mail_message_id.needaction_partner_ids = [(6, 0, partner_ids)]
|
||||
return True
|
||||
|
||||
def get_user_email(self, line):
|
||||
# for line in line_ids:
|
||||
user_ids = self.env['res.groups'].search([('id', 'in', line.group_ids.ids)])
|
||||
user_email = []
|
||||
partner_ids = []
|
||||
for user in user_ids:
|
||||
for rec in user.users:
|
||||
partner_ids.append(rec.partner_id.id)
|
||||
user_email.append(rec.partner_id.email)
|
||||
user_email = list(set(user_email))
|
||||
emails = ''
|
||||
for email in user_email:
|
||||
emails += email + ','
|
||||
return emails,partner_ids
|
||||
|
||||
def action_send_late_email(self):
|
||||
late_record = self.env['late.email.reminder'].search([], limit=1)
|
||||
if late_record.line_ids:
|
||||
states = ['cancel']
|
||||
for line in late_record.line_ids:
|
||||
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
|
||||
user_email,partner_ids = self.get_user_email(line)
|
||||
for state in line.record_state_ids:
|
||||
states.append(state.name)
|
||||
model_name = line.model_id.model
|
||||
record = self.env[model_name].search([('state', 'not in', states)])
|
||||
for rec in record:
|
||||
order_date = rec.mapped(line.order_date.name)
|
||||
last_date = ''
|
||||
if order_date[0]:
|
||||
if len(order_date[0]) > 10:
|
||||
last_date = datetime.strptime(order_date[0], DATE_FORMAT).date()
|
||||
else:
|
||||
last_date = datetime.strptime(order_date[0], DATE).date()
|
||||
end_date = last_date + timedelta(days=self.number_of_days)
|
||||
date_now = date.today()
|
||||
if end_date < date_now:
|
||||
mail_id = self.send_message(line.template_id, rec, model_name, user_email,partner_ids)
|
||||
|
||||
|
||||
class LateEmailReminderLine(models.Model):
|
||||
_name = "late.email.reminder.line"
|
||||
|
||||
model_id = fields.Many2one('ir.model', string='Model')
|
||||
order_date = fields.Many2one('ir.model.fields', string='Order Date')
|
||||
record_state_ids = fields.Many2many('late.email.state', string='States')
|
||||
template_id = fields.Many2one('mail.template', string='Template')
|
||||
late_email_id = fields.Many2one('late.email.reminder', string='Late Email')
|
||||
group_ids = fields.Many2many('res.groups', string='Groups')
|
||||
|
||||
@api.onchange('model_id')
|
||||
def onchange_model_id(self):
|
||||
domain = {}
|
||||
self.order_date = False
|
||||
domain = {'order_date': [('id', 'in', self.env['ir.model.fields'].search([('model_id', '=', self.model_id.id),
|
||||
'|', ('ttype', '=', 'date'),
|
||||
('ttype', '=', 'datetime')]).ids)],
|
||||
'template_id': [('id', 'in', self.env['mail.template'].search([('model_id', '=', self.model_id.id)]).ids)]
|
||||
}
|
||||
return {'domain': domain}
|
||||
|
||||
|
||||
class LateEmailState(models.Model):
|
||||
_name = 'late.email.state'
|
||||
|
||||
name = fields.Char(string='name of state')
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,247 @@
|
|||
.circle{
|
||||
position: fixed;
|
||||
top: 5.5%;
|
||||
left: 1%;
|
||||
z-index:99;
|
||||
height: 30%;
|
||||
width: 20%;
|
||||
color:black;
|
||||
}
|
||||
|
||||
.footer{
|
||||
color: black;
|
||||
margin-top: 400;
|
||||
background-color: white;
|
||||
|
||||
}
|
||||
|
||||
.button_div{
|
||||
background: #1c9980;
|
||||
width : 50px;
|
||||
height: 50px;
|
||||
color:white;
|
||||
}
|
||||
|
||||
.notifier-container{
|
||||
background: #fff;
|
||||
height: 100%;
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
box-shadow: 0 8px 14px 0 rgba(0, 0, 0, 0.38);
|
||||
border-left: 1px solid #eee;
|
||||
z-index: 100;
|
||||
transform: translateX(400px);
|
||||
transition: all .5s ease-in-out;
|
||||
overflow: scroll;
|
||||
}
|
||||
.notifier-container h3{
|
||||
border-bottom: 1px solid #1c9980;
|
||||
padding: 20px 10px 5px 10px;
|
||||
}
|
||||
.notifier-container .notifier-body{
|
||||
padding: 0 10px;
|
||||
}
|
||||
.notifier-container .notifier-body .alert{
|
||||
margin-bottom: 5px;
|
||||
background-color: #3E5D7F;
|
||||
color: white;
|
||||
}
|
||||
.notifier-container .notifier-body ul{
|
||||
padding: 0;
|
||||
}
|
||||
.notifier-container .notifier-body ul li a:nth-child(1){
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
.notifier-container .notifier-body ul li a:nth-child(2){
|
||||
float: right;
|
||||
}
|
||||
.notifier-overlayer{
|
||||
display: none;
|
||||
background: #00000061;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
.notifier-button{
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
bottom: -100px;
|
||||
right: 45%;
|
||||
z-index: 99;
|
||||
transition: all .5s ease-in-out;
|
||||
}
|
||||
|
||||
.containers {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width:210px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.rectangle {
|
||||
/* display: flex;
|
||||
text-align: center; */
|
||||
justify-content: flex-start;
|
||||
/* position: relative; */
|
||||
width: 50px;
|
||||
height: 55px;
|
||||
background: #3E5D7F;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
border-radius: 50%;
|
||||
color: white;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rectangle.animate{
|
||||
-webkit-animation: scale-in .4s ease-out forwards, expand .45s .35s ease-out forwards;
|
||||
animation: scale-in .4s ease-out forwards, expand .45s .35s ease-out forwards;
|
||||
}
|
||||
.rectangle.animate-out{
|
||||
-webkit-animation: scale-out .3s ease-in forwards, expand-out .35s .25s ease-in forwards;
|
||||
animation: scale-out .3s ease-in forwards, expand-out .35s .25s ease-in forwards;
|
||||
}
|
||||
.notification-text .badge{
|
||||
background-color: #f51212;
|
||||
font-size: 14px;
|
||||
margin: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.notification-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 14px;
|
||||
font-family: 'Arial', sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.notification-text.animate{
|
||||
-webkit-animation: fade-in .65s ease-in forwards;
|
||||
animation: fade-in .65s ease-in forwards;
|
||||
}
|
||||
.notification-text.animate-out{
|
||||
-webkit-animation: fade-out .65s ease-out backwards;
|
||||
animation: fade-out .65s ease-out backwards;
|
||||
}
|
||||
|
||||
|
||||
@-webkit-keyframes scale-in {
|
||||
100% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scale-in {
|
||||
100% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes expand {
|
||||
50% {
|
||||
width: 350px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
100% {
|
||||
width: 300px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 3px 3px -1px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
}
|
||||
@keyframes expand {
|
||||
50% {
|
||||
width: 350px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
100% {
|
||||
width: 300px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 3px 3px -1px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes scale-out {
|
||||
100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scale-out {
|
||||
100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes expand-out {
|
||||
50% {
|
||||
width: 350px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 3px 3px -1px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
100% {
|
||||
width: 50px;
|
||||
border-radius: 50%;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
@keyframes expand-out {
|
||||
50% {
|
||||
width: 350px;
|
||||
border-radius: 6px;
|
||||
box-shadow: none;
|
||||
}
|
||||
100% {
|
||||
width: 50px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes fade-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes fade-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
odoo.define('exp_late_mail_reminder.notification_popup', function (require) {
|
||||
"use strict";
|
||||
//this file migrate from odoo9 to 11 written by altaher migrate by fatima 18/5/2020
|
||||
var core = require('web.core');
|
||||
var ajax = require('web.ajax');
|
||||
var QWeb = core.qweb;
|
||||
var rpc = require('web.rpc');
|
||||
var ActionManager = require('web.ActionManager');
|
||||
var Widget = require('web.Widget');
|
||||
var ControlPanelMixin = require('web.ControlPanelMixin');
|
||||
//
|
||||
function save_hashing(url) {
|
||||
var _id = '';
|
||||
var p1 = /&action=\d+/g;
|
||||
var record_id = url.match(p1);
|
||||
if (record_id) {
|
||||
_id = record_id[0].match(/\d+\d*/g)[0];
|
||||
try {
|
||||
var h = $.md5(_id.toString(), (new Date()).getFullYear().toString());
|
||||
localStorage.setItem("navigator_token", h);
|
||||
localStorage.setItem("navigator_token_act", _id);
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function save_hashing_record(url) {
|
||||
var rec = '';
|
||||
|
||||
try {
|
||||
var p1 = /#id=\d+/g;
|
||||
var record_id = url.match(p1);
|
||||
if (record_id) {
|
||||
rec = record_id[0].match(/\d+\d*/g)[0];
|
||||
var h = $.md5((new Date()).getFullYear().toString(), rec.toString());
|
||||
localStorage.setItem("record_token", h);
|
||||
localStorage.setItem("origin_record_id", rec);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
}
|
||||
$(document).ready(function () {
|
||||
function dragElement(elmnt) {
|
||||
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
||||
if (document.getElementById(elmnt.id + "header")) {
|
||||
/* if present, the header is where you move the DIV from:*/
|
||||
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
|
||||
} else {
|
||||
/* otherwise, move the DIV from anywhere inside the DIV:*/
|
||||
elmnt.onmousedown = dragMouseDown;
|
||||
}
|
||||
|
||||
function dragMouseDown(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// get the mouse cursor position at startup:
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
document.onmouseup = closeDragElement;
|
||||
// call a function whenever the cursor moves:
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// calculate the new cursor position:
|
||||
pos1 = pos3 - e.clientX;
|
||||
pos2 = pos4 - e.clientY;
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
// set the element's new position:
|
||||
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
|
||||
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
/* stop moving when mouse button is released:*/
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
}
|
||||
}
|
||||
function load_message_loader() {
|
||||
return ajax.jsonRpc('/reminder/notifications', 'call', {})
|
||||
.then(function (results) {
|
||||
if (results.length > 0) {
|
||||
var content = '';
|
||||
var no_message = results.length
|
||||
$('body').append('<div class="notifier-container"><h2 style="color:#204060;">التنبيهات</h2><div class="col-md-12 notifier-body"></div></div>');
|
||||
$('body').append('<div class="notifier-overlayer"></div>');
|
||||
$('body').append('<div class="notifier-button style="dir:ltr"><div class="containers"><div class="rectangle"><div class="notification-text"><span><strong>لديك رسائل جديدة</span><span class="badge" id="badge">'+ no_message+'</span></strong></div></div></div></div>');
|
||||
_.each(results, function (item) {
|
||||
$('.notifier-body').append('<div data-id='+ item['id']+' class="alert alert-warning"><ul class="list-unstyled"><li><a href="'+item['base_url']+'/web#id='+ item['res_id']+'&view_type=form&model='+item['res_model']+'&action='+item['action_id'] +'">'+'<p style="color : white;"> '+item['subject'] +'</p></a></li></ul></div>');
|
||||
});
|
||||
var alert = document.querySelectorAll('.alert')
|
||||
$(alert).click(function (event) {
|
||||
var id = $(event.currentTarget).data('id');
|
||||
var MessageModel = rpc.query({
|
||||
model: 'mail.message',
|
||||
method: 'mark_all_as_read',
|
||||
args:[[],[['id','=',id]]]
|
||||
}).then(
|
||||
function () {
|
||||
$(event.currentTarget).hide();
|
||||
no_message = no_message - 1;
|
||||
$('#badge').text(no_message);
|
||||
$(".notifier-overlayer").fadeOut();
|
||||
$(".notifier-container").css({"transform":"translateX(400px)"});
|
||||
if(no_message > 0){
|
||||
$(".rectangle-text").addClass("animate");
|
||||
$(".rectangle").addClass("animate");
|
||||
$(".notifier-button").css({"bottom":"20px"});
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
console.log(id);
|
||||
});
|
||||
$(".rectangle").click(function(){
|
||||
$(".notifier-overlayer").show();
|
||||
$(".notifier-container").css({"transform":"translateX(0)"});
|
||||
$(".notifier-button").css({"bottom":"-100px"});
|
||||
$(".rectangle-text").removeClass("animate");
|
||||
$(".rectangle").removeClass("animate");
|
||||
});
|
||||
$(".notifier-overlayer").click(function(){
|
||||
$(".notifier-overlayer").fadeOut();
|
||||
$(".notifier-container").css({"transform":"translateX(400px)"});
|
||||
$(".rectangle-text").addClass("animate");
|
||||
$(".rectangle").addClass("animate");
|
||||
$(".notifier-button").css({"bottom":"20px"});
|
||||
});
|
||||
|
||||
$(".rectangle-text").addClass("animate");
|
||||
$(".rectangle").addClass("animate");
|
||||
$(".notifier-button").css({"bottom":"20px"});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(load_message_loader, 2000);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="notification_template">
|
||||
<!-- <div class="ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix ui-draggable-handle">
|
||||
رسائل جديدة (<t t-esc="message_no" />)
|
||||
</div>
|
||||
<table class="o_list_view table table-condensed table-striped" id="messages_table">
|
||||
<thead>
|
||||
<th>رقم الرسالة</th>
|
||||
<th>الموضوع</th>
|
||||
<th style="text-align :center">استلام</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr t-foreach="data" t-as="rec" t-att-data-id="rec.id" t-att-data-res_model="rec.res_model" t-att-data-res_id="rec.res_id" t-att-data-base_url="rec.base_url" class="message_rec">
|
||||
<td><span t-esc="rec.id"/></td>
|
||||
<td><span t-esc="rec.subject" /></td>
|
||||
<td style="text-align :center"><button class="o_icon_button" type="button" title="إستلام المعاملة"><i class="fa fa-check" title="إستلام المعاملة" /></button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix">
|
||||
<div class="ui-dialog-buttonset">
|
||||
<div class="btn btn-primary btn-sm" id="close" type="object" title="إستلام المعاملة">إغلاق</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!--add by fatima-ahmed 17/5/2020 to migration code of notify in -->
|
||||
<template id="assets_backend_custom" name="autocomplete assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/exp_late_mail_reminder/static/src/css/style.css"/>
|
||||
<script type="text/javascript" src="/exp_late_mail_reminder/static/src/js/notification_popup.js"/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id='view_late_mail_reminder_form' model='ir.ui.view'>
|
||||
<field name="name">late.mail.reminder.form</field>
|
||||
<field name="model">late.email.reminder</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Late Email Reminder" class="oe_form_configuration">
|
||||
<header>
|
||||
<button string="Apply" type="object" name="execute" class="oe_highlight"/>
|
||||
<!-- <div>-->
|
||||
<!-- or-->
|
||||
<!-- </div>-->
|
||||
<!-- <div/>-->
|
||||
<!-- <button string="Cancel" type="object" name="cancel" class="oe_link"/>-->
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="number_of_days" required="1"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<notebook>
|
||||
<page string="Email Late Line">
|
||||
<group>
|
||||
<field name="line_ids" nolabel="1">
|
||||
<form string="Late Email Line">
|
||||
<group>
|
||||
<group>
|
||||
<field name="model_id"/>
|
||||
<field name="order_date"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="record_state_ids" widget="many2many_tags"/>
|
||||
<field name="group_ids" widget="many2many_tags"/>
|
||||
<field name="template_id"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
<tree string="Late Email Lines" editable="bottom">
|
||||
<field name="model_id" required="1"/>
|
||||
<field name="order_date" required="1"/>
|
||||
<field name="record_state_ids" widget="many2many_tags" required="1"/>
|
||||
<field name="group_ids" widget="many2many_tags" required="1"/>
|
||||
<field name="template_id" required="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id='action_late_email_reminder' model='ir.actions.act_window'>
|
||||
<field name="name">late Email Reminder</field>
|
||||
<field name="res_model">late.email.reminder</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="res_id" ref="exp_late_mail_reminder.exp_late_email_reminder"/>
|
||||
<field name="target">inline</field>
|
||||
</record>
|
||||
<menuitem action="action_late_email_reminder" name="Late Email Reminder" parent="base.menu_email"
|
||||
id="menu_late_reminder_email" sequence="115"/>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odex - Communications Management System.
|
||||
# Copyright (C) 2019 Expert Co. Ltd. (<http://exp-sa.com>).
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'Multi-level Transaction Management',
|
||||
'version': '1.0',
|
||||
'sequence': 4,
|
||||
'author': 'Expert Co. Ltd.',
|
||||
'category': 'Odex25-Transactions/Odex25-Transactions',
|
||||
'summary': 'Multi-level management of transactions',
|
||||
'description': """
|
||||
Odex - Communications Management System
|
||||
========================================
|
||||
Multi-level management of transactions
|
||||
""",
|
||||
'website': 'http://www.exp-sa.com',
|
||||
'depends': ['exp_transaction_documents'],
|
||||
'data': [
|
||||
'views/extend_entity.xml',
|
||||
],
|
||||
'qweb' : [
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': True,
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import extend_entity
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api,_
|
||||
# from odoo.exceptions import Warning
|
||||
|
||||
|
||||
class Entity(models.Model):
|
||||
_inherit = 'cm.entity'
|
||||
_description = 'for mange transaction in multi level'
|
||||
|
||||
manager_entity = fields.Many2many(comodel_name='cm.entity', relation='manage_entity_rel', column1='manager_id',
|
||||
column2='entity_id', string='Owners of powers')
|
||||
need_multi_approve = fields.Boolean(string='Need Multi level Approve')
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!--inherit entity view -->
|
||||
<record id="entity_view_inherit_form" model="ir.ui.view">
|
||||
<field name="name">extend.transaction.form</field>
|
||||
<field name="model">cm.entity</field>
|
||||
<field name="inherit_id" ref="exp_transaction_documents.cm_entity_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='need_approve']" position="after">
|
||||
<field name="need_multi_approve" attrs="{'invisible': [('type', 'not in', ['unit'])]}"/>
|
||||
<field name="manager_entity" domain="[('type', '=', 'employee')]" options="{'no_create_edit': True}"
|
||||
widget="many2many_tags" attrs="{'invisible': [('need_multi_approve', '!=', True)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/exp_transaction.iml" filepath="$PROJECT_DIR$/.idea/exp_transaction.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="3ff197a9-0b96-4ea8-9e34-af98cfa90616" name="Default Changelist" comment="" />
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/__manifest__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="300">
|
||||
<caret line="20" column="16" selection-start-line="20" selection-start-column="16" selection-end-line="20" selection-end-column="16" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/models/configuration.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="225">
|
||||
<caret line="15" column="26" selection-start-line="15" selection-start-column="26" selection-end-line="15" selection-end-column="26" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="IdeDocumentHistory">
|
||||
<option name="CHANGED_PATHS">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/__manifest__.py" />
|
||||
<option value="$PROJECT_DIR$/models/configuration.py" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds" extendedState="6">
|
||||
<option name="x" value="133" />
|
||||
<option name="y" value="47" />
|
||||
<option name="width" value="1380" />
|
||||
<option name="height" value="833" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator proportions="" version="1">
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="ProjectPane" />
|
||||
<pane id="Scope" />
|
||||
</panes>
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="3ff197a9-0b96-4ea8-9e34-af98cfa90616" name="Default Changelist" comment="" />
|
||||
<created>1555402175295</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1555402175295</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="67" y="25" width="1533" height="875" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<layout>
|
||||
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.24966888" />
|
||||
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||
<window_info id="Favorites" order="2" side_tool="true" />
|
||||
<window_info anchor="bottom" id="Message" order="0" />
|
||||
<window_info anchor="bottom" id="Find" order="1" />
|
||||
<window_info anchor="bottom" id="Run" order="2" />
|
||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
<window_info anchor="bottom" id="TODO" order="6" />
|
||||
<window_info anchor="bottom" id="Version Control" order="7" />
|
||||
<window_info anchor="bottom" id="Terminal" order="8" />
|
||||
<window_info anchor="bottom" id="Event Log" order="9" side_tool="true" />
|
||||
<window_info anchor="bottom" id="Python Console" order="10" />
|
||||
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
|
||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/__manifest__.py</url>
|
||||
<line>20</line>
|
||||
<option name="timeStamp" value="1" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/__manifest__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="300">
|
||||
<caret line="20" column="16" selection-start-line="20" selection-start-column="16" selection-end-line="20" selection-end-column="16" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/models/configuration.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="225">
|
||||
<caret line="15" column="26" selection-start-line="15" selection-start-column="26" selection-end-line="15" selection-end-column="26" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
from . import wizard
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odex - Communications Management System.
|
||||
# Copyright (C) 2019 Expert Co. Ltd. (<http://exp-sa.com>).
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'Communications Management',
|
||||
'version': '1.0',
|
||||
'sequence': 4,
|
||||
'author': 'Expert Co. Ltd.',
|
||||
'category': 'Odex25-Transactions/Odex25-Transactions',
|
||||
'summary': 'Correspondence Management System',
|
||||
'description': """
|
||||
Odex - Communications Management System
|
||||
========================================
|
||||
Managing Communications Transcations flows
|
||||
""",
|
||||
'website': 'http://www.exp-sa.com',
|
||||
'depends': ['base', 'base_odex', 'mail', 'html_text', 'odex_sms'],
|
||||
'data': [
|
||||
'security/groups.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'email_templates/out_templates.xml',
|
||||
'data/cm_data.xml',
|
||||
'data/ir_cron.xml',
|
||||
'views/entity.xml',
|
||||
'views/configuration.xml',
|
||||
'views/transcation_common_view.xml',
|
||||
'views/internal.xml',
|
||||
'views/incoming.xml',
|
||||
'views/outgoing.xml',
|
||||
'reports/transaction_details_report_template.xml',
|
||||
'reports/receiver_transaction_report_template.xml',
|
||||
# 'views/settings_config_view.xml',
|
||||
'views/actions_and_menus.xml',
|
||||
'wizard/reject_transaction_reson.xml',
|
||||
'wizard/forward_transaction.xml',
|
||||
'wizard/archive_transaction.xml',
|
||||
'wizard/transaction_reply_wizard.xml',
|
||||
'wizard/reopen_transaction_wizard.xml',
|
||||
'email_templates/internal_templates.xml',
|
||||
'email_templates/incoming_templates.xml',
|
||||
|
||||
],
|
||||
'qweb': [
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': True,
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="seq_cm_entity" model="ir.sequence">
|
||||
<field name="name">Entities Seq</field>
|
||||
<field name="code">cm.entity</field>
|
||||
<field name="prefix"></field>
|
||||
<field name="suffix"></field>
|
||||
<field name="padding">3</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="seq_cm_transaction_out" model="ir.sequence">
|
||||
<field name="name">Outgointg Transactions Seq</field>
|
||||
<field name="code">cm.transaction.out</field>
|
||||
<field name="prefix">%(year)s/2</field>
|
||||
<field name="suffix"></field>
|
||||
<field name="padding">4</field>
|
||||
</record>
|
||||
|
||||
<record id="seq_cm_transaction_in" model="ir.sequence">
|
||||
<field name="name">Incoming Transactions Seq</field>
|
||||
<field name="code">cm.transaction.in</field>
|
||||
<field name="prefix">%(year)s/3</field>
|
||||
<field name="suffix"></field>
|
||||
<field name="padding">4</field>
|
||||
</record>
|
||||
|
||||
<record id="seq_cm_transaction_internal" model="ir.sequence">
|
||||
<field name="name">Internal Transactions Seq</field>
|
||||
<field name="code">cm.transaction.internal</field>
|
||||
<field name="prefix">%(year)s/1</field>
|
||||
<field name="suffix"></field>
|
||||
<field name="padding">4</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record model="ir.cron" id="late_transaction_mail">
|
||||
<field name="name">تأخر المعاملات عن وقت الانتهاء</field>
|
||||
<field name="active">True</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model_id" ref="model_internal_transaction" />
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.late_transaction_cron()</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<record id="incoming_notify_send_send_email" model="mail.template">
|
||||
<field name="name">Transaction Send Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_incoming_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.get_email()|safe}</field>
|
||||
<field name="subject"><![CDATA[ معاملة خارجية واردة ]]></field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right">السادة الفضلاء: ${object.get_name()}</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right;direction: ltr;float: left;">
|
||||
توجد معاملة خارجية واردة للمعاملة
|
||||
</p><br/>
|
||||
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و تنفيذ الإجراء المطلوب
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,719 @@
|
|||
<odoo>
|
||||
<data>
|
||||
|
||||
|
||||
<record id="internal_approval1_request_email" model="mail.template">
|
||||
<field name="name">Unit Manager Request Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${object.employee_id.name} <${(object.employee_id.user_id.partner_id.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.preparation_id.manager_id.user_id.partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[ إعتماد الإدارة لمعاملة داخلية موجهة الى ]]> ${object.to_ids[0].name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right"> ،، ${object.preparation_id.manager_id.name|safe} - السادة الفضلاء</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
توجد معاملة داخلية في انتظار اعتماد الإدارة
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>موجهة الى : </b></td>
|
||||
<td style="text-decoration:underline">${object.to_ids[0].name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : موضوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : نوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : الإدارة المعدة</b></td>
|
||||
<td style="text-decoration:underline">${object.preparation_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : معِد المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : آخر موعد لإنجاز المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
</p>
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record id="internal_ready_email" model="mail.template">-->
|
||||
<!-- <field name="name">Transaction Ready for send Message</field>-->
|
||||
<!-- <field name="model_id" ref="cm_odex.model_cm_transaction_internal"/>-->
|
||||
<!-- <field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>-->
|
||||
<!-- <field name="email_to">${object.employee_id.user_id.partner_id.email|safe}</field>-->
|
||||
<!-- <field name="subject"><![CDATA[ تم إعتماد الإدارة لمعاملة موجهة الى ]]> ${object.to_ids[0].name|safe} <![CDATA[ بالرقم ]]> ${object.name|safe}</field>-->
|
||||
<!-- <field name="body_html">-->
|
||||
<!-- <![CDATA[-->
|
||||
<!-- <div style="text-align: right;direction:rtl">-->
|
||||
<!-- <p style="text-align: right"> ،، ${object.employee_id.name} - السادة الفضلاء</p>-->
|
||||
<!-- <p style="text-align: left">حفظهم الله،،</p>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- السلام عليكم ورحمة الله.-->
|
||||
<!-- -->
|
||||
<!-- </p>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- تم اعتماد الادارة للمعاملة-->
|
||||
<!-- </p><br/>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- يمكنكم الان المتابعة و إرسال المعاملة المطلوبة -->
|
||||
<!-- </p><br/>-->
|
||||
<!-- <p style="font-size: 1em;text-align: right">-->
|
||||
<!-- <table>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b>رقم المعاملة : </b></td>-->
|
||||
<!-- <td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b>موجهة إالى : </b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.to_ids[0].name}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b> : موضوع المعاملة</b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.subject}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b> : نوع المعاملة</b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.subject_type_id.name}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b> : معِد المعاملة</b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.employee_id.name}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b> : آخر موعد لإنجاز المعاملة</b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.due_date}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- </table> -->
|
||||
<!-- </p><br/>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- <a href="${object.get_url()}">رابط المعاملة</a>-->
|
||||
<!-- </p>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- <a href="${user.company_id.website}">${user.company_id.name}</a>-->
|
||||
<!-- -->
|
||||
<!-- -->
|
||||
<!-- </p>-->
|
||||
|
||||
<!-- </div>-->
|
||||
<!-- ]]>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
|
||||
<!-- <record id="internal_ready_email2" model="mail.template">-->
|
||||
<!-- <field name="name">Transaction Ready for send Message</field>-->
|
||||
<!-- <field name="model_id" ref="cm_odex.model_cm_transaction_internal"/>-->
|
||||
<!-- <field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>-->
|
||||
<!-- <field name="email_to">${object.employee_id.user_id.partner_id.email|safe}</field>-->
|
||||
<!-- <field name="subject"><![CDATA[ تم إعتماد القسم لمعاملة موجهة الى ]]> ${object.to_ids[0].name|safe} <![CDATA[ بالرقم ]]> ${object.name|safe}</field>-->
|
||||
<!-- <field name="body_html">-->
|
||||
<!-- <![CDATA[-->
|
||||
<!-- <div style="text-align: right;direction:rtl">-->
|
||||
<!-- <p style="text-align: right"> ،، ${object.employee_id.name} - السادة الفضلاء</p>-->
|
||||
<!-- <p style="text-align: left">حفظهم الله،،</p>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- السلام عليكم ورحمة الله.-->
|
||||
|
||||
<!-- </p>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- تم اعتماد القسم للمعاملة رقم-->
|
||||
<!-- </p><br/>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- يمكنكم الان المتابعة و إرسال المعاملة المطلوبة-->
|
||||
<!-- </p><br/>-->
|
||||
<!-- <p style="font-size: 1em;text-align: right">-->
|
||||
<!-- <table>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b>رقم المعاملة : </b></td>-->
|
||||
<!-- <td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b>موجهة إالى : </b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.to_ids[0].name}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b> : موضوع المعاملة</b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.subject}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b> : نوع المعاملة</b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.subject_type_id.name}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b> : معِد المعاملة</b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.employee_id.name}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <td><b> : آخر موعد لإنجاز المعاملة</b></td>-->
|
||||
<!-- <td style="text-decoration:underline">${object.due_date}</td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- </table>-->
|
||||
<!-- </p><br/>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right;">-->
|
||||
<!-- <a href="${object.get_url()}">رابط المعاملة</a>-->
|
||||
<!-- </p>-->
|
||||
<!-- <p style="font-size: 1.1em;text-align: right">-->
|
||||
<!-- <a href="${user.company_id.website}">${user.company_id.name}</a>-->
|
||||
|
||||
|
||||
<!-- </p>-->
|
||||
|
||||
<!-- </div>-->
|
||||
<!-- ]]>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
|
||||
<record id="internal_notify_forward_email" model="mail.template">
|
||||
<field name="name">Transaction forward Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.forward_user_id.partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[ إحالة واردة: معاملة داخلية بالرقم ]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right">السادة الفضلاء: ${object.forward_user_id.name}</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
توجد إحالة واردة للمعاملة
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و تنفيذ الإجراء المطلوب
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>محالة من قِبل : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_forward().from_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>الإجراء المطلوب : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_forward().procedure_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>تاريخ الإحالة : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_forward().date}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
</p>
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="internal_notify_reply_email" model="mail.template">
|
||||
<field name="name">Transaction Reply Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.last_forwarded_user.partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[ رد على إحالة: معاملة داخلية بالرقم ]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right">السادة الفضلاء: ${object.employee_id.name}</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
تم الرد على الإحالة للمعاملة
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و إكمال اللازم
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موجه من : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('reply').from_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>الإجراء المطلوب : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('reply').procedure_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> الملاحظات : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('reply').note}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>تاريخ الإحالة : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('reply').date}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
</p>
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="internal_notify_close_email" model="mail.template">
|
||||
<field name="name">Transaction Close Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.employee_id.user_id.partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[ حفظ المعاملة بالرقم ]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
تم حفظ المعاملة
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>مبرر الحفظ : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('archive').archive_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> الملاحظات : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('archive').note}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>تاريخ الحفظ : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('archive').date}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
</p>
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="internal_notify_send_send_email" model="mail.template">
|
||||
<field name="name">Transaction Send Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.get_email()|safe}</field>
|
||||
<field name="subject"><![CDATA[ تم ارسال المعاملة : معاملة داخلية بالرقم ]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right">السادة الفضلاء: ${object.get_name()}</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
توجد معاملة مرسلة
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و تنفيذ الإجراء المطلوب
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
</p>
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="internal_reopen_transaction_email" model="mail.template">
|
||||
<field name="name">Reopen Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.employee_id.user_id.partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[ إعادة فتح المعاملة]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right">السادة الفضلاء: ${object.employee_id.name}</p>
|
||||
<p style="text-align: center">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
تم اعادة فتح المعاملة
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>الإجراء المطلوب : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('reopen').procedure_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> الملاحظات : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('reopen').note}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>تاريخ اعادة فتح المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('reopen').date}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و تنفيذ الإجراء المطلوب
|
||||
</p><br/>
|
||||
<br/>
|
||||
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="internal_return_transaction_email" model="mail.template">
|
||||
<field name="name">Return Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.employee_id.user_id.partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[ إرجاع المعاملة]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right">السادة الفضلاء: ${object.employee_id.name}</p>
|
||||
<p style="text-align: center">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
تم إرجاع المعاملة
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b> الملاحظات : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('return').note}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>تاريخ إرجاع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('return').date}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و تنفيذ الإجراء المطلوب
|
||||
</p><br/>
|
||||
<br/>
|
||||
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="internal_reject_transaction_email" model="mail.template">
|
||||
<field name="name">Reject Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.employee_id.user_id.partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[رفض المعاملة]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right">السادة الفضلاء: ${object.employee_id.name}</p>
|
||||
<p style="text-align: center">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
تم رفض المعاملة
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><b> اسباب الرفض : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('refuse').note}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>تاريخ رفض المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.get_latest_by_action('refuse').date}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و تنفيذ الإجراء المطلوب
|
||||
</p><br/>
|
||||
<br/>
|
||||
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
</p>
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="internal_late_transaction_email" model="mail.template">
|
||||
<field name="name">Late Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_internal_transaction"/>
|
||||
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.get_email()}</field>
|
||||
<field name="subject"><![CDATA[تأخر المعاملة]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right">السادة الفضلاء: ${object.employee_id.name}</p>
|
||||
<p style="text-align: center">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
تأخر معاملة
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>موضوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>نوع المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> معِد المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> آخر موعد لانجاز المعاملة : </b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و تنفيذ الإجراء المطلوب
|
||||
</p><br/>
|
||||
<br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
</p>
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="out_approval1_request_email" model="mail.template">
|
||||
<field name="name">Unit Manager Approval Request Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_outgoing_transaction"/>
|
||||
<field name="email_from">
|
||||
<![CDATA[${object.employee_id.name} <${(object.employee_id.user_id.partner_id.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.preparation_id.manager_id.user_id.partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[ إعتماد معاملة صادر موجهة الى ]]> ${object.to_ids[0].name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right"> ،، ${object.preparation_id.manager_id.name} - السادة الفضلاء</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
توجد معاملة صادر جديدة في انتظار اعتماد مسئول الوحدة (${object.preparation_id.name})
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>جهة الصادر : </b></td>
|
||||
<td style="text-decoration:underline">${object.to_ids[0].name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : موضوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : نوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : معِد المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : آخر موعد لإنجاز المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="out_approval2_request_email" model="mail.template">
|
||||
<field name="name">CEO Approval Request Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_outgoing_transaction"/>
|
||||
<field name="email_from">
|
||||
<![CDATA[${object.employee_id.name} <${(object.employee_id.user_id.partner_id.email)|safe}>]]></field>
|
||||
<field name="email_to">${object.get_second_manager().partner_id.email|safe}</field>
|
||||
<field name="subject"><![CDATA[ إعتماد الإدارة التنفيذية لمعاملة صادر موجهة الى ]]>
|
||||
${object.to_ids[0].name|safe}
|
||||
</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right"> ،، ${object.get_second_manager().name|safe} - السادة الفضلاء</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
توجد معاملة صادر جديدة في انتظار اعتماد الإدارة التنفيذية
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>جهة الصادر : </b></td>
|
||||
<td style="text-decoration:underline">${object.to_ids[0].name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : موضوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : نوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : معِد المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : الإدارة المعدّة</b></td>
|
||||
<td style="text-decoration:underline">${object.preparation_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : آخر موعد لإنجاز المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="out_ready_email" model="mail.template">
|
||||
<field name="name">Transaction Ready for send Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_outgoing_transaction"/>
|
||||
<field name="email_from">
|
||||
<![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">
|
||||
${object.preparation_id.manager_id.user_id.partner_id.email|safe},${object.employee_id.user_id.partner_id.email|safe}
|
||||
</field>
|
||||
<field name="subject"><![CDATA[ تم إعتماد الإدارة التنفيذية لمعاملة صادر موجهة الى ]]>
|
||||
${object.to_ids[0].name|safe} <![CDATA[ بالرقم ]]> ${object.name|safe}
|
||||
</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right"> ،، ${object.employee_id.name} - السادة الفضلاء</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
تم اعتماد الادارة التنفيذية لمعاملة الصادر
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
يمكنكم الان المتابعة و ترميز المعاملة كمرسل حال اكتمال اجراءات الارسال،،
|
||||
</p><br/>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>جهة الصادر : </b></td>
|
||||
<td style="text-decoration:underline">${object.to_ids[0].name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : موضوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : نوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : معِد المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : آخر موعد لإنجاز المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.due_date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
<record id="out_email" model="mail.template">
|
||||
<field name="name">Transaction Ready for send Message</field>
|
||||
<field name="model_id" ref="exp_transaction_documents.model_outgoing_transaction"/>
|
||||
<field name="email_from">
|
||||
<![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||
<field name="email_to">
|
||||
${object.preparation_id.manager_id.user_id.partner_id.email|safe},${object.employee_id.user_id.partner_id.email|safe}
|
||||
</field>
|
||||
<field name="subject">${object.to_ids[0].name|safe} <![CDATA[ بالرقم ]]> ${object.name|safe}</field>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<div style="text-align: right;direction:rtl">
|
||||
<p style="text-align: right"> ،، ${object.employee_id.name} - السادة الفضلاء</p>
|
||||
<p style="text-align: left">حفظهم الله،،</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
السلام عليكم ورحمة الله.
|
||||
</p>
|
||||
<p style="font-size: 1em;text-align: right">
|
||||
<table>
|
||||
<tr>
|
||||
<td><b>رقم المعاملة : </b></td>
|
||||
<td style="text-decoration:underline;direction: ltr;float: left;">${object.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>جهة الصادر : </b></td>
|
||||
<td style="text-decoration:underline">${object.to_ids[0].name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : موضوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : نوع المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.subject_type_id.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b> : معِد المعاملة</b></td>
|
||||
<td style="text-decoration:underline">${object.employee_id.name}</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</p><br/>
|
||||
<p style="font-size: 1.1em;text-align: right;">
|
||||
<a href="${object.get_url()}">رابط المعاملة</a>
|
||||
</p>
|
||||
<p style="font-size: 1.1em;text-align: right">
|
||||
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import entity
|
||||
from . import configuration
|
||||
# from . import res_config_settings
|
||||
from . import transaction
|
||||
from . import internal_transaction
|
||||
from . import outgoing_transaction
|
||||
from . import incoming_transaction
|
||||
from . import tools
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, api, fields, _
|
||||
|
||||
TRACE_ACTIONS = [
|
||||
('forward', _('Forwarded')),
|
||||
('receive', _('Received')),
|
||||
('archive', _('Archived')),
|
||||
('approve', _('Unit Manager Approved')),
|
||||
('ceo_approve', _('CEO Approved')),
|
||||
('sent', _('Sent')),
|
||||
('return', _('Returned')),
|
||||
('action', _('Action Taken')),
|
||||
('refuse', _('Refused')),
|
||||
('reply', _('Replied')),
|
||||
('waite', _('Waiting Approve')),
|
||||
('reopen', _('Reopened')),
|
||||
]
|
||||
|
||||
|
||||
class SubjectType(models.Model):
|
||||
_name = 'cm.subject.type'
|
||||
_order = 'sequence'
|
||||
|
||||
name = fields.Char(string='Transaction Type')
|
||||
sequence = fields.Integer(string='Sequence', default=5)
|
||||
second_approval = fields.Boolean(string='Second Approval ?',
|
||||
help='Check if this transaction type need a second (CEO) Approval.', default=True)
|
||||
transaction_need_approve = fields.Boolean(string="Transaction need approve")
|
||||
tran_tag = fields.Many2many(comodel_name='transaction.tag', string='Tags')
|
||||
|
||||
|
||||
class ImportantDegree(models.Model):
|
||||
_name = 'cm.transaction.important'
|
||||
|
||||
name = fields.Char(string='Important Degree')
|
||||
rank = fields.Integer(string='Transaction Rank')
|
||||
|
||||
|
||||
class Procedure(models.Model):
|
||||
_name = 'cm.procedure'
|
||||
|
||||
name = fields.Char(string='Procedure Name')
|
||||
|
||||
|
||||
class AttachmentType(models.Model):
|
||||
_name = 'cm.attachment.type'
|
||||
|
||||
sequence = fields.Integer(string='Sequence', default=1)
|
||||
name = fields.Char(string='Name')
|
||||
|
||||
|
||||
class Attachment(models.Model):
|
||||
_name = 'cm.attachment'
|
||||
|
||||
name = fields.Char(string='Description')
|
||||
num_page = fields.Integer(string='No. Pages')
|
||||
type_id = fields.Many2one('cm.attachment.type', string='Attachment type')
|
||||
incoming_transaction_id = fields.Many2one(comodel_name='incoming.transaction', string='Incoming Transaction')
|
||||
internal_transaction_id = fields.Many2one(comodel_name='internal.transaction', string='Internal Transaction')
|
||||
outgoing_transaction_id = fields.Many2one(comodel_name='outgoing.transaction', string='Outgoing Transaction')
|
||||
|
||||
|
||||
class ArchiveType(models.Model):
|
||||
_name = 'cm.archive.type'
|
||||
|
||||
name = fields.Char(string='Archive Type')
|
||||
|
||||
|
||||
class AttachmentRule(models.Model):
|
||||
_name = 'cm.attachment.rule'
|
||||
|
||||
def _default_employee_id(self):
|
||||
user = self.env.user
|
||||
em = self.env['cm.entity'].search([('user_id', '=', user.id)], limit=1)
|
||||
return len(em) and em or self.env['cm.entity']
|
||||
|
||||
name = fields.Char()
|
||||
employee_id = fields.Many2one(comodel_name='cm.entity', string='Created By',
|
||||
default=lambda self: self._default_employee_id(), readonly="True")
|
||||
entity_id = fields.Many2one(comodel_name='cm.entity', string='Unit Responsible', related='employee_id.parent_id',
|
||||
store=True)
|
||||
file_save = fields.Binary('Save File')
|
||||
attachment_filename = fields.Char(string="Attachment Filename")
|
||||
incoming_transaction_id = fields.Many2one(comodel_name='incoming.transaction', string='Incoming Transaction')
|
||||
internal_transaction_id = fields.Many2one(comodel_name='internal.transaction', string='Internal Transaction')
|
||||
outgoing_transaction_id = fields.Many2one(comodel_name='outgoing.transaction', string='Outgoing Transaction')
|
||||
date = fields.Datetime(string='Date', default=fields.Datetime.now)
|
||||
description = fields.Char(string='Description')
|
||||
|
||||
|
||||
class TransactionTrace(models.Model):
|
||||
_name = 'cm.transaction.trace'
|
||||
_description = 'Transaction Trace'
|
||||
_order = 'date desc'
|
||||
|
||||
action = fields.Selection(string='Action', selection=TRACE_ACTIONS, default='forward')
|
||||
incoming_transaction_id = fields.Many2one(comodel_name='incoming.transaction', string='Incoming Transaction')
|
||||
internal_transaction_id = fields.Many2one(comodel_name='internal.transaction', string='Internal Transaction')
|
||||
outgoing_transaction_id = fields.Many2one(comodel_name='outgoing.transaction', string='Outgoing Transaction')
|
||||
date = fields.Datetime(string='Date', default=fields.Datetime.now)
|
||||
from_id = fields.Many2one(comodel_name='cm.entity', string='From')
|
||||
to_id = fields.Many2one(comodel_name='cm.entity', string='To')
|
||||
procedure_id = fields.Many2one(comodel_name='cm.procedure', string='Action Taken')
|
||||
note = fields.Char(string='Notes')
|
||||
archive_type_id = fields.Many2one(comodel_name='cm.archive.type', string='Archive Type')
|
||||
cc_ids = fields.Many2many('cm.entity', string='CC To')
|
||||
|
||||
|
||||
class ProjectType(models.Model):
|
||||
_name = "project.type"
|
||||
|
||||
name = fields.Char(string='Name')
|
||||
sequence = fields.Integer(string='Sequence', default=1)
|
||||
|
||||
|
||||
class TransactionCategory(models.Model):
|
||||
_name = 'transaction.tag'
|
||||
|
||||
name = fields.Char("Name")
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from odoo import models, api, fields, _
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
|
||||
|
||||
class JobTitle(models.Model):
|
||||
_name = 'cm.job.title'
|
||||
_description = 'Job Titles'
|
||||
|
||||
name = fields.Char(string='Job Title')
|
||||
|
||||
|
||||
class Entity(models.Model):
|
||||
_name = 'cm.entity'
|
||||
_description = 'Transactions Contacts'
|
||||
_order = 'name'
|
||||
|
||||
@api.model
|
||||
def _name_search(self, name, args=None, operator='like', limit=100, name_get_uid=None):
|
||||
args = args or []
|
||||
domain = []
|
||||
if name:
|
||||
domain = ['|', ('name', operator, name), ('code', operator, name)]
|
||||
print(domain)
|
||||
return self._search(domain + args, limit=limit, access_rights_uid=name_get_uid)
|
||||
|
||||
@api.constrains('code')
|
||||
def _check_code(self):
|
||||
count = self.search_count([('code', '=', self.code), ('id', '!=', self.id)])
|
||||
if self.code:
|
||||
if count:
|
||||
raise ValidationError(_("Validation Error Entity Code Must Be unique !"))
|
||||
if self.type == 'unit':
|
||||
x = ''
|
||||
if len(self.code) == 3 or len(self.code) == 2:
|
||||
x = 'a'
|
||||
if self.code.isalpha() == False or x == '':
|
||||
raise ValidationError(_("Validation Error Entity Code Must Be Composed from 3/2 characters"))
|
||||
|
||||
code = fields.Char(string='Code')
|
||||
# sequence = fields.Integer(string='Sequence')
|
||||
partner_id = fields.Many2one(comodel_name='res.partner', string='Partner', readonly=False, ondelete='cascade',
|
||||
copy=False)
|
||||
name = fields.Char(string='Name', store=True)
|
||||
type = fields.Selection(string='Entity Type', selection=[('unit', _('Internal Unit')), ('employee', _('Employee')),
|
||||
('external', _('External Unit'))], default='unit')
|
||||
parent_id = fields.Many2one(comodel_name='cm.entity', string='Parent Entity')
|
||||
department_id = fields.Many2one('hr.department')
|
||||
manager_id = fields.Many2one(comodel_name='cm.entity', string='Unit Manager')
|
||||
secretary_id = fields.Many2one(comodel_name='cm.entity', string='Employee in charge of transactions')
|
||||
user_id = fields.Many2one(comodel_name='res.users', string='Related User', related='employee_id.user_id')
|
||||
# job_title_id = fields.Many2one(comodel_name='cm.job.title', string='Job Title')
|
||||
job_title_id = fields.Many2one(comodel_name='hr.job', string='Job Title')
|
||||
need_approve = fields.Boolean(string='Need Aprove')
|
||||
executive_direction = fields.Boolean(string='Executive direction')
|
||||
is_secret = fields.Boolean(string='Is Secret')
|
||||
person_id = fields.Char(string='Person ID')
|
||||
person_id_issue_date = fields.Date(string='Person ID Issue Date')
|
||||
employee_assignment_date = fields.Date(string='Employee Assignment Date')
|
||||
employee_id = fields.Many2one('hr.employee')
|
||||
phone = fields.Char()
|
||||
email = fields.Char()
|
||||
child_ids = fields.Many2many(comodel_name='cm.entity', relation='employee_entity_rel', column1='employee_id',
|
||||
column2='entity_id', string='Related Units')
|
||||
establish_date = fields.Date(string='Establish Date')
|
||||
unit_location = fields.Char(string='Unit Location')
|
||||
sketch_attachment_id = fields.Many2one(comodel_name='ir.attachment', string='Sketch Attachment')
|
||||
dynamic_year = fields.Char(string='Year', default=datetime.datetime.now().strftime('%Y'))
|
||||
year_increment = fields.Boolean(string='Continue Increment every year?', help='''
|
||||
Check if you want to continue incrementing in the start of every new year.
|
||||
''', default=True)
|
||||
|
||||
@api.onchange('department_id')
|
||||
def onchange_department_id(self):
|
||||
self.name = self.department_id.name
|
||||
|
||||
@api.onchange('employee_id')
|
||||
def onchange_employee_id(self):
|
||||
self.job_title_id = self.employee_id.job_id
|
||||
self.name = self.employee_id.name
|
||||
self.person_id = self.employee_id.iqama_number.iqama_id
|
||||
self.email = self.employee_id.personal_email
|
||||
self.phone = self.employee_id.mobile_phone
|
||||
self.person_id_issue_date = self.employee_id.iqama_number.expiry_date
|
||||
# self.employee_assignment_date = self.employee_id.job_id
|
||||
|
||||
@api.onchange('partner_id')
|
||||
def onchange_partner_id(self):
|
||||
self.name = self.partner_id.name
|
||||
self.email = self.partner_id.email
|
||||
self.phone = self.partner_id.phone
|
||||
|
||||
####################################################
|
||||
# ORM Overrides methods
|
||||
####################################################
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('type', False) == 'employee':
|
||||
vals['partner_id'] = self.env['hr.employee'].search(
|
||||
[('id', '=', vals['employee_id'])]).user_id.partner_id.id
|
||||
if 'partner_id' not in vals:
|
||||
print("*******************")
|
||||
if vals.get('type', False) == 'employee':
|
||||
user_id = vals.get('user_id', False)
|
||||
if user_id:
|
||||
vals['partner_id'] = self.env['res.users'].search([('id', '=', user_id)]).partner_id.id
|
||||
else:
|
||||
partner = self.env['res.partner'].create({
|
||||
'name': vals.get('name', ''),
|
||||
'email': vals.get('email', ''),
|
||||
'city': vals.get('city', _('Riyadh')),
|
||||
'is_company': vals.get('is_company', True),
|
||||
'country_id': self.env.ref('base.sa', True).id,
|
||||
})
|
||||
vals['partner_id'] = partner.id
|
||||
sequence = {
|
||||
'employee': '01',
|
||||
'unit': '02',
|
||||
'external': '03',
|
||||
}
|
||||
if not vals.get('code', False):
|
||||
seq = self.env['ir.sequence'].get('cm.entity')
|
||||
s = u'{}-{}'.format(sequence[vals.get('type', 'employee')], seq)
|
||||
|
||||
if vals.get('type') == 'employee' or vals.get('type') == 'external':
|
||||
vals['code'] = s
|
||||
return super(Entity, self).create(vals)
|
||||
|
||||
def write(self, vals):
|
||||
sequence = {
|
||||
'employee': '01',
|
||||
'unit': '02',
|
||||
'external': '03',
|
||||
}
|
||||
if not vals.get('code', False):
|
||||
seq = self.env['ir.sequence'].get('cm.entity')
|
||||
s = u'{}-{}'.format(sequence[vals.get('type', 'employee')], seq)
|
||||
if vals.get('type') == 'employee' or vals.get('type') == 'external':
|
||||
vals['code'] = s
|
||||
return super(Entity, self).write(vals)
|
||||
|
||||
def copy(self, default=None):
|
||||
raise UserError(_('You cannot duplicate an entity!'))
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
is_transaction_entity = fields.Boolean('Is Transaction Entity?')
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
res = super(ResPartner, self).create(values)
|
||||
if values.get('is_transaction_entity'):
|
||||
entity = self.env['cm.entity'].create({
|
||||
'name': values.get('name', ''),
|
||||
'partner_id': values.get('id'),
|
||||
})
|
||||
return res
|
||||
|
||||
def write(self, vals):
|
||||
res = super(ResPartner, self).write(vals)
|
||||
if vals.get('is_transaction_entity'):
|
||||
if not self.env['cm.entity'].search([('partner_id', '=', self.id)]):
|
||||
entity = self.env['cm.entity'].create({
|
||||
'name': self.name,
|
||||
'partner_id': vals.get('id'),
|
||||
})
|
||||
return res
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, api, fields, _
|
||||
from odoo.exceptions import ValidationError
|
||||
from datetime import datetime
|
||||
from hijri_converter import convert, Hijri
|
||||
|
||||
|
||||
class IncomingTransaction(models.Model):
|
||||
_name = 'incoming.transaction'
|
||||
_inherit = ['transaction.transaction', 'mail.thread']
|
||||
_description = 'incoming Transaction'
|
||||
|
||||
# due_date = fields.Date(string='Deadline', compute='compute_due_date')
|
||||
from_id = fields.Many2one(comodel_name='cm.entity', string='Incoming From (External)')
|
||||
partner_id = fields.Many2one('res.partner')
|
||||
outgoing_transaction_id = fields.Many2one('outgoing.transaction', string='Related Outgoing')
|
||||
incoming_number = fields.Char(string='Incoming Number')
|
||||
incoming_date = fields.Date(string='Incoming Date', default=fields.Date.today)
|
||||
incoming_date_hijri = fields.Char(string='Incoming Date (Hijri)', compute='_compute_incoming_date_hijri')
|
||||
attachment_rule_ids = fields.One2many('cm.attachment.rule', 'incoming_transaction_id', string='Attaches')
|
||||
attachment_ids = fields.One2many('cm.attachment', 'incoming_transaction_id', string='Attachments')
|
||||
trace_ids = fields.One2many('cm.transaction.trace', 'incoming_transaction_id', string='Trace Log')
|
||||
to_ids = fields.Many2many(comodel_name='cm.entity', relation='incoming_entity_rel', column1='incoming_id'
|
||||
, column2='entity_id', string='Send To')
|
||||
cc_ids = fields.Many2many(comodel_name='cm.entity', relation='incoming_entity_cc_rel',
|
||||
column1='incoming_id', column2='entity_id', string='CC To')
|
||||
tran_tag = fields.Many2many(comodel_name='transaction.tag', string='Tags')
|
||||
tran_tag_unit = fields.Many2many(comodel_name='transaction.tag', string='Business unit',
|
||||
relation='incoming_tag_rel',
|
||||
column1='incoming_id'
|
||||
, column2='name')
|
||||
project_id = fields.Many2many('project.project')
|
||||
sale_order_id = fields.Many2one('sale.order', 'Proposal')
|
||||
processing_ids = fields.Many2many(comodel_name='incoming.transaction', relation='transaction_incoming_incoming_rel',
|
||||
column1='transaction_id', column2='incoming_id',
|
||||
string='Process Transactions incoming')
|
||||
processing2_ids = fields.Many2many(comodel_name='outgoing.transaction',
|
||||
relation='transaction_incoming_outgoing_rel',
|
||||
column1='transaction_id', column2='outgoing_id',
|
||||
string='Process Transactions Outgoing')
|
||||
attachment_count = fields.Integer(compute='count_attachments')
|
||||
# attachment_file = fields.Many2many(
|
||||
# comodel_name='ir.attachment',
|
||||
# string='')
|
||||
|
||||
datas = fields.Binary(string="", related='send_attach.datas')
|
||||
|
||||
def count_attachments(self):
|
||||
obj_attachment = self.env['ir.attachment']
|
||||
for record in self:
|
||||
record.attachment_count = 0
|
||||
attachment_ids = obj_attachment.search(
|
||||
[('res_model', '=', 'incoming.transaction'), ('res_id', '=', record.id)])
|
||||
first_file = []
|
||||
if attachment_ids:
|
||||
first_file.append(attachment_ids[0].id)
|
||||
# print(first_file)
|
||||
# record.attachment_file = first_file
|
||||
record.attachment_count = len(attachment_ids)
|
||||
|
||||
@api.model
|
||||
def get_url(self):
|
||||
url = u''
|
||||
action = self.env.ref(
|
||||
'exp_transaction_documents.forward_incoming_external_tran_action', False)
|
||||
Param = self.env['ir.config_parameter'].sudo()
|
||||
if action:
|
||||
return u'{}/web#id={}&action={}&model=incoming.transaction'.format(
|
||||
Param.get_param('web.base.url', self.env.user.company_id.website), self.id, action.id)
|
||||
return url
|
||||
|
||||
@api.depends('incoming_date')
|
||||
def _compute_incoming_date_hijri(self):
|
||||
for rec in self:
|
||||
if rec.incoming_date:
|
||||
gregorian_date = fields.Date.from_string(rec.incoming_date)
|
||||
hijri_date = convert.Gregorian(gregorian_date.year, gregorian_date.month, gregorian_date.day).to_hijri()
|
||||
rec.incoming_date_hijri = hijri_date
|
||||
else:
|
||||
rec.incoming_date_hijri = ''
|
||||
|
||||
@api.depends('attachment_rule_ids')
|
||||
def compute_attachment_num(self):
|
||||
for r in self:
|
||||
r.attachment_num = len(r.attachment_rule_ids)
|
||||
|
||||
def fetch_sequence(self):
|
||||
'''generate transaction sequence'''
|
||||
return self.env['ir.sequence'].next_by_code('cm.transaction.in') or _('New')
|
||||
|
||||
####################################################
|
||||
# Business methods
|
||||
####################################################
|
||||
|
||||
def action_draft(self):
|
||||
for record in self:
|
||||
res = super(IncomingTransaction, self).action_send()
|
||||
|
||||
# Check if to_ids is not empty before accessing its first element
|
||||
if record.to_ids:
|
||||
employee = self.current_employee()
|
||||
to_id = record.to_ids[0].id
|
||||
|
||||
if record.to_ids[0].type != 'employee':
|
||||
to_id = record.to_ids[0].secretary_id.id
|
||||
|
||||
record.trace_ids.create({
|
||||
'action': 'sent',
|
||||
'to_id': to_id,
|
||||
'from_id': employee and employee.id or False,
|
||||
'procedure_id': record.procedure_id.id or False,
|
||||
'incoming_transaction_id': record.id
|
||||
})
|
||||
|
||||
partner_ids = []
|
||||
for partner in record.to_ids:
|
||||
if partner.type == 'unit':
|
||||
partner_ids.append(partner.secretary_id.user_id.partner_id.id)
|
||||
record.forward_user_id = partner.secretary_id.user_id.id
|
||||
elif partner.type == 'employee':
|
||||
partner_ids.append(partner.user_id.partner_id.id)
|
||||
record.forward_user_id = partner.user_id.id
|
||||
|
||||
subj = _('Message Has been send !')
|
||||
msg = _(u'{} ← {}').format(record.employee_id.name, u' / '.join([k.name for k in record.to_ids]))
|
||||
msg = u'{}<br /><b>{}</b> {}.<br />{}'.format(msg,
|
||||
_(u'Action Taken'), record.procedure_id.name,
|
||||
u'<a href="%s" >رابط المعاملة</a> ' % (
|
||||
record.get_url()))
|
||||
|
||||
self.action_send_notification(subj, msg, partner_ids)
|
||||
template = 'exp_transaction_documents.incoming_notify_send_send_email'
|
||||
self.send_message(template=template)
|
||||
|
||||
return res
|
||||
|
||||
def action_send_forward(self):
|
||||
template = 'exp_transaction_documents.incoming_notify_send_send_email'
|
||||
self.send_message(template=template)
|
||||
|
||||
def action_reply_internal(self):
|
||||
name = 'default_incoming_transaction_id'
|
||||
return self.action_reply_tran(name, self)
|
||||
|
||||
def action_forward_incoming(self):
|
||||
name = 'default_incoming_transaction_id'
|
||||
return self.action_forward_tran(name, self)
|
||||
|
||||
def action_archive_incoming(self):
|
||||
name = 'default_incoming_transaction_id'
|
||||
return self.action_archive_tran(name, self)
|
||||
|
||||
####################################################
|
||||
# ORM Overrides methods
|
||||
####################################################
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
seq = self.fetch_sequence()
|
||||
if vals['preparation_id']:
|
||||
code = self.env['cm.entity'].browse(vals['preparation_id']).code
|
||||
x = seq.split('/')
|
||||
sequence = "%s/%s/%s" % (x[0], code, x[1])
|
||||
vals['name'] = sequence
|
||||
else:
|
||||
vals['name'] = seq
|
||||
vals['ean13'] = self.env['odex.barcode'].code128('IN', vals['name'], 'TR')
|
||||
return super(IncomingTransaction, self).create(vals)
|
||||
#
|
||||
#
|
||||
# def unlink(self):
|
||||
# if self.env.uid != 1:
|
||||
# raise ValidationError(_("You can not delete transaction....."))
|
||||
# return super(IncomingTransaction, self).unlink()
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from datetime import datetime
|
||||
from odoo import models, api, fields, _
|
||||
|
||||
|
||||
class InternalTransaction(models.Model):
|
||||
_name = 'internal.transaction'
|
||||
_inherit = ['transaction.transaction', 'mail.thread']
|
||||
_description = 'internal Transaction'
|
||||
|
||||
# due_date = fields.Date(string='Deadline', compute='_compute_due_date')
|
||||
reason = fields.Text('Reason')
|
||||
attachment_rule_ids = fields.One2many('cm.attachment.rule', 'internal_transaction_id', string='Attaches')
|
||||
attachment_ids = fields.One2many('cm.attachment', 'internal_transaction_id', string='Attachments')
|
||||
trace_ids = fields.One2many('cm.transaction.trace', 'internal_transaction_id', string='Trace Log')
|
||||
type_sender = fields.Selection(
|
||||
string='',
|
||||
selection=[('unit', 'Unit'),
|
||||
('employee', 'Employee'),
|
||||
],
|
||||
required=False, default='unit')
|
||||
|
||||
to_ids = fields.Many2many(comodel_name='cm.entity', relation='internal_entity_rel', column1='internal_id'
|
||||
, column2='entity_id', string='Send To')
|
||||
partner_id = fields.Many2one('res.partner', string='Partner', readonly=True,
|
||||
related='to_ids.secretary_id.partner_id')
|
||||
cc_ids = fields.Many2many(comodel_name='cm.entity', relation='internal_entity_cc_rel',
|
||||
column1='internal_id', column2='entity_id', string='CC To')
|
||||
project_domain = fields.Many2many('project.project', string='Project Domain')
|
||||
processing_ids = fields.Many2many(comodel_name='internal.transaction', relation='transaction_internal_rel',
|
||||
column1='transaction_id', column2='internal_id', string='Process Transactions')
|
||||
|
||||
@api.model
|
||||
def get_url(self):
|
||||
url = u''
|
||||
action = self.env.ref(
|
||||
'exp_transaction_documents.incoming_internal_tran_action', False)
|
||||
Param = self.env['ir.config_parameter'].sudo()
|
||||
if action:
|
||||
return u'{}/web#id={}&action={}&model=internal.transaction'.format(
|
||||
Param.get_param('web.base.url', self.env.user.company_id.website), self.id, action.id)
|
||||
return url
|
||||
|
||||
@api.depends('attachment_rule_ids')
|
||||
def compute_attachment_num(self):
|
||||
for r in self:
|
||||
r.attachment_num = len(r.attachment_rule_ids)
|
||||
|
||||
def fetch_sequence(self, data=None):
|
||||
'''generate transaction sequence'''
|
||||
return self.env['ir.sequence'].get('cm.transaction.internal') or _('New')
|
||||
|
||||
####################################################
|
||||
# Business methods
|
||||
####################################################
|
||||
|
||||
def action_draft(self):
|
||||
for record in self:
|
||||
"""her i need to review code for to_ids"""
|
||||
res = super(InternalTransaction, self).action_draft()
|
||||
sent = 'sent'
|
||||
template = 'exp_transaction_documents.internal_notify_send_send_email'
|
||||
if record.subject_type_id.transaction_need_approve or record.preparation_id.need_approve:
|
||||
template = 'exp_transaction_documents.internal_approval1_request_email'
|
||||
sent = 'waite'
|
||||
record.trace_create_ids('internal_transaction_id', record, sent)
|
||||
partner_ids = []
|
||||
for partner in record.to_ids:
|
||||
if partner.type == 'unit':
|
||||
partner_ids.append(partner.secretary_id.user_id.partner_id.id)
|
||||
record.forward_user_id = partner.secretary_id.user_id.id
|
||||
elif partner.type == 'employee':
|
||||
partner_ids.append(partner.user_id.partner_id.id)
|
||||
record.forward_user_id = partner.user_id.id
|
||||
if record.to_user_have_leave:
|
||||
record.forward_user_id = record.receive_id.user_id.id
|
||||
record.send_message(template=template)
|
||||
subj = _('Message Has been send !')
|
||||
msg = _(u'{} ← {}').format(record.employee_id.name, u' / '.join([k.name for k in record.to_ids]))
|
||||
msg = u'{}<br /><b>{}</b> {}.<br />{}'.format(msg,
|
||||
_(u'Action Taken'), record.procedure_id.name,
|
||||
u'<a href="%s" >رابط المعاملة</a> ' % (
|
||||
record.get_url()))
|
||||
company_id = self.env.user.company_id
|
||||
if company_id.sms_active == True:
|
||||
message = "There is a transaction that needs to " + self.procedure_id.name if self.procedure_id else ""
|
||||
message += " with the number " + self.name
|
||||
print(record.employee_id.employee_id.phone)
|
||||
print(message)
|
||||
request = company_id.send_sms(str(record.employee_id.employee_id.phone), message if message else "")
|
||||
for rec in record:
|
||||
rec.action_send_notification(subj, msg, partner_ids)
|
||||
return res
|
||||
|
||||
def action_approve(self):
|
||||
res = super(InternalTransaction, self).action_approve()
|
||||
template = 'exp_transaction_documents.internal_notify_send_send_email'
|
||||
self.send_message(template=template)
|
||||
employee = self.current_employee()
|
||||
to_id = self.to_ids[0].id
|
||||
if self.to_ids[0].type != 'employee':
|
||||
to_id = self.to_ids[0].secretary_id.id
|
||||
self.trace_ids.create({
|
||||
'action': 'sent',
|
||||
'to_id': to_id,
|
||||
'from_id': employee and employee.id or False,
|
||||
'procedure_id': self.procedure_id.id or False,
|
||||
'internal_transaction_id': self.id
|
||||
})
|
||||
# self.trace_create_ids('internal_transaction_id', self, 'sent')
|
||||
subj = _('Message Has been approved !')
|
||||
msg = _(u'{} ← {}').format(self.preparation_id.manager_id.name, u' / '.join([k.name for k in self.to_ids]))
|
||||
msg = u'{}<br /><b>{}</b> {}.<br />{}'.format(msg,
|
||||
_(u'Action Taken'), self.procedure_id.name,
|
||||
u'<a href="%s" >رابط المعاملة</a> ' % (
|
||||
self.get_url()))
|
||||
partner_ids = [self.employee_id.user_id.partner_id.id, self.to_ids[0].user_id.partner_id.id]
|
||||
self.action_send_notification(subj, msg, partner_ids)
|
||||
return res
|
||||
|
||||
def action_reject_internal(self):
|
||||
name = 'default_internal_transaction_id'
|
||||
return self.action_reject(name, self)
|
||||
|
||||
def action_return_internal(self):
|
||||
name = 'default_internal_transaction_id'
|
||||
return self.action_return_tran(name, self)
|
||||
|
||||
def action_forward_internal(self):
|
||||
name = 'default_internal_transaction_id'
|
||||
return self.action_forward_tran(name, self)
|
||||
|
||||
def action_reply_internal(self):
|
||||
name = 'default_internal_transaction_id'
|
||||
return self.action_reply_tran(name, self)
|
||||
|
||||
def action_archive_internal(self):
|
||||
name = 'default_internal_transaction_id'
|
||||
return self.action_archive_tran(name, self)
|
||||
|
||||
def action_reopen_internal(self):
|
||||
name = 'default_internal_transaction_id'
|
||||
return self.action_reopen_tran(name, self)
|
||||
|
||||
def get_latest_forward(self):
|
||||
for rec in self:
|
||||
return rec.trace_ids.filtered(lambda z: z.action == 'forward')[0]
|
||||
|
||||
def get_latest_by_action(self, action):
|
||||
for rec in self:
|
||||
return rec.trace_ids.filtered(lambda z: z.action == action)[0]
|
||||
|
||||
def action_send_forward(self):
|
||||
template = 'exp_transaction_documents.internal_notify_forward_email'
|
||||
self.send_message(template=template)
|
||||
|
||||
def action_send_reply(self):
|
||||
template = 'exp_transaction_documents.internal_notify_reply_email'
|
||||
self.send_message(template=template)
|
||||
|
||||
def action_send_close(self):
|
||||
template = 'exp_transaction_documents.internal_notify_close_email'
|
||||
self.send_message(template=template)
|
||||
|
||||
def action_reopen_email(self):
|
||||
template = 'exp_transaction_documents.internal_reopen_transaction_email'
|
||||
self.send_message(template=template)
|
||||
|
||||
def action_reject_email(self):
|
||||
template = 'exp_transaction_documents.internal_reject_transaction_email'
|
||||
self.send_message(template=template)
|
||||
|
||||
def action_return_email(self):
|
||||
template = 'exp_transaction_documents.internal_return_transaction_email'
|
||||
self.send_message(template=template)
|
||||
|
||||
def late_transaction_cron(self):
|
||||
templates = 'exp_transaction_documents.internal_late_transaction_email'
|
||||
transaction_ids = self.env['internal.transaction'].search([('state', 'in', ['send', 'reply'])])
|
||||
if transaction_ids:
|
||||
today = fields.date.today()
|
||||
for transaction in transaction_ids:
|
||||
if datetime.strptime(transaction.due_date, "%Y-%m-%d") < datetime.strptime(str(today), "%Y-%m-%d"):
|
||||
rec = transaction.trace_ids.filtered(lambda z: z.action == 'forward' or z.action == 'sent' or
|
||||
z.action == 'reply')[0]
|
||||
template = self.env.ref(templates, False)
|
||||
template.write({'email_to': rec.to_id.user_id.partner_id.email,
|
||||
'email_cc': rec.to_id.parent_id.manager_id.user_id.partner_id.email})
|
||||
template.with_context(lang=self.env.user.lang).send_mail(
|
||||
transaction.id, force_send=True, raise_exception=False)
|
||||
|
||||
####################################################
|
||||
# ORM Overrides methods
|
||||
####################################################
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
seq = self.fetch_sequence()
|
||||
if vals.get('preparation_id', False):
|
||||
code = self.env['cm.entity'].browse(vals['preparation_id']).code
|
||||
x = seq.split('/')
|
||||
sequence = "%s/%s/%s" % (x[0], code, x[1])
|
||||
vals['name'] = sequence
|
||||
else:
|
||||
vals['name'] = seq
|
||||
return super(InternalTransaction, self).create(vals)
|
||||
|
||||
#
|
||||
# def unlink(self):
|
||||
# if self.env.uid != 1:
|
||||
# raise ValidationError(_("You can not delete transaction....."))
|
||||
# return super(InternalTransaction, self).unlink()
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, api, fields, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class OutgoingTransaction(models.Model):
|
||||
_name = 'outgoing.transaction'
|
||||
_inherit = ['transaction.transaction', 'mail.thread']
|
||||
_description = 'outgoing Transaction'
|
||||
|
||||
reason = fields.Text('Reason')
|
||||
attachment_rule_ids = fields.One2many('cm.attachment.rule', 'outgoing_transaction_id', string='Attaches')
|
||||
attachment_ids = fields.One2many('cm.attachment', 'outgoing_transaction_id', string='Attachments')
|
||||
trace_ids = fields.One2many('cm.transaction.trace', 'outgoing_transaction_id', string='Trace Log')
|
||||
is_partner = fields.Boolean()
|
||||
partner_id = fields.Many2one('res.partner')
|
||||
incoming_transaction_id = fields.Many2one('incoming.transaction', string='Related Incoming')
|
||||
to_ids = fields.Many2many(comodel_name='cm.entity', relation='outgoing_entity_rel', column1='outgoing_id'
|
||||
, column2='entity_id', string='Send To')
|
||||
tran_tag = fields.Many2many(comodel_name='transaction.tag', string='Tags')
|
||||
tran_tag_unit = fields.Many2many(comodel_name='transaction.tag', string='Business unit',
|
||||
relation='outgoing_tag_rel',
|
||||
column1='incoming_id'
|
||||
, column2='name')
|
||||
project_id = fields.Many2many('project.project')
|
||||
sale_order_id = fields.Many2one('sale.order', 'Proposal')
|
||||
to_name = fields.Char(string="Recipient")
|
||||
cc_ids = fields.Many2many(comodel_name='cm.entity', relation='outgoing_entity_cc_rel',
|
||||
column1='outgoing_id', column2='entity_id', string='CC To')
|
||||
processing_ids = fields.Many2many(comodel_name='outgoing.transaction', relation='transaction_outgoing_outgoing_rel',
|
||||
column1='transaction_id', column2='outgoing_id',
|
||||
string='Process Transactions outgoing')
|
||||
processing2_ids = fields.Many2many(comodel_name='incoming.transaction',
|
||||
relation='transaction_outgoing_incoming_rel',
|
||||
column1='transaction_id', column2='incoming_id',
|
||||
string='Process Transactions incoming')
|
||||
|
||||
# processing_ids = fields.Many2many(comodel_name='transaction.transaction', relation='transaction_outgoing_rel',
|
||||
# column1='transaction_id', column2='outgoing_id', string='Process Transactions')
|
||||
|
||||
@api.depends('attachment_rule_ids')
|
||||
def compute_attachment_num(self):
|
||||
for r in self:
|
||||
r.attachment_num = len(r.attachment_rule_ids)
|
||||
|
||||
@api.model
|
||||
def get_url(self):
|
||||
url = u''
|
||||
action = self.env.ref(
|
||||
'exp_transaction_documents.outgoing_external_tran_action', False)
|
||||
Param = self.env['ir.config_parameter'].sudo()
|
||||
if action:
|
||||
return u'{}/web#id={}&action={}&model=outgoing.transaction'.format(
|
||||
Param.get_param('web.base.url', self.env.user.company_id.website), self.id, action.id)
|
||||
return url
|
||||
|
||||
def fetch_sequence(self, data=None):
|
||||
"""generate transaction sequence"""
|
||||
return self.env['ir.sequence'].next_by_code('cm.transaction.out') or _('New')
|
||||
|
||||
####################################################
|
||||
# Business methods
|
||||
####################################################
|
||||
#
|
||||
|
||||
def action_draft(self):
|
||||
for record in self:
|
||||
"""her i need to review code for to_ids"""
|
||||
# res = super(OutgoingTransaction, self).action_draft()
|
||||
if record.subject_type_id.transaction_need_approve or record.preparation_id.need_approve:
|
||||
record.state = 'to_approve'
|
||||
else:
|
||||
record.state = 'complete'
|
||||
# record.trace_create_ids('outgoing_transaction_id', record, 'sent')
|
||||
partner_ids = [record.preparation_id.manager_id.user_id.partner_id.id]
|
||||
subj = _('Message Has been send !')
|
||||
msg = _(u'{} ← {}').format(record.employee_id.name, u' / '.join([k.name for k in record.to_ids]))
|
||||
msg = u'{}<br /><b>{}</b> {}.<br />{}'.format(msg,
|
||||
_(u'Action Taken'), record.procedure_id.name,
|
||||
u'<a href="%s" >رابط المعاملة</a> ' % (
|
||||
record.get_url()))
|
||||
self.action_send_notification(subj, msg, partner_ids)
|
||||
# return res
|
||||
|
||||
def action_email(self):
|
||||
# todo#add email function here
|
||||
company_id = self.env.user.company_id
|
||||
if company_id.sms_active == True:
|
||||
test = company_id.send_sms("", "Test from odex!")
|
||||
test = test.text[:100].split("-")
|
||||
error = company_id.get_error_response(test[1])
|
||||
for rec in self:
|
||||
templates = 'exp_transaction_documents.out_email'
|
||||
template = self.env.ref(templates, False)
|
||||
emails = rec.partner_id.email if rec.is_partner else rec.to_ids.mapped('email')
|
||||
email_template = template.write(
|
||||
{'email_to': emails})
|
||||
template.with_context(lang=self.env.user.lang).send_mail(
|
||||
rec.id, force_send=True, raise_exception=False)
|
||||
|
||||
def action_reject_outgoing(self):
|
||||
name = 'default_outgoing_transaction_id'
|
||||
return self.action_reject(name, self)
|
||||
|
||||
def action_return_outgoing(self):
|
||||
name = 'default_outgoing_transaction_id'
|
||||
return self.action_return_tran(name, self)
|
||||
|
||||
####################################################
|
||||
# ORM Overrides methods
|
||||
####################################################
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
seq = self.fetch_sequence()
|
||||
if vals.get('preparation_id'):
|
||||
code = self.env['cm.entity'].sudo().browse(vals['preparation_id']).code
|
||||
x = seq.split('/')
|
||||
sequence = "%s/%s/%s" % (x[0], code, x[1])
|
||||
vals['name'] = sequence
|
||||
else:
|
||||
vals['name'] = seq
|
||||
# vals['ean13'] = self.env['odex.barcode'].code128('OT', vals['name'], 'TR')
|
||||
return super(OutgoingTransaction, self).create(vals)
|
||||
|
||||
#
|
||||
# def unlink(self):
|
||||
# if self.env.uid != 1:
|
||||
# raise ValidationError(_("You can not delete transaction....."))
|
||||
# return super(OutgoingTransaction, self).unlink()
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
|
||||
class CMConfig(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
module_cm_hr_odex = fields.Boolean(string='Synchronization With HR ?', help='''
|
||||
If checked, you will be able to sync employees, departments, job titles with Crosspondence Tracking System.
|
||||
''')
|
||||
module_cm_mail_odex = fields.Boolean(string='Convert Email Messages to Transactions', help='''
|
||||
If checked, you can convert emails to Incoming Transactions.
|
||||
''')
|
||||
last_date_to_execute_transaction = fields.Boolean(string='Last Date To Execute Transaction', help='''
|
||||
If checked, you add rank value to start date to get last date to execute Transaction.
|
||||
''')
|
||||
|
||||
# ir.values is not exited in odoo 11 so i use ir.config_parameter instead of ir.value 15 Apr
|
||||
@api.model
|
||||
def get_values(self):
|
||||
res = super(CMConfig, self).get_values()
|
||||
res.update(
|
||||
last_date_to_execute_transaction=self.env['ir.config_parameter'].sudo().get_param('exp_transaction_documents.last_date_to_execute_transaction'),
|
||||
module_cm_mail_odex=self.env['ir.config_parameter'].sudo().get_param('exp_transaction_documents.module_cm_mail_odex'),
|
||||
module_cm_hr_odex=self.env['ir.config_parameter'].sudo().get_param('exp_transaction_documents.module_cm_hr_odex')
|
||||
)
|
||||
return res
|
||||
|
||||
|
||||
def set_values(self):
|
||||
super(CMConfig, self).set_values()
|
||||
self.env['ir.config_parameter'].sudo().set_param('exp_transaction_documents.last_date_to_execute_transaction', self.last_date_to_execute_transaction)
|
||||
self.env['ir.config_parameter'].sudo().set_param('exp_transaction_documents.module_cm_mail_odex', self.module_cm_mail_odex)
|
||||
self.env['ir.config_parameter'].sudo().set_param('exp_transaction_documents.module_cm_hr_odex', self.module_cm_hr_odex)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
"""
|
||||
create(vals) -> record
|
||||
Override create to change last_date_to_execute_transaction_id value in cm.subject.type
|
||||
"""
|
||||
res = super(CMConfig, self).create(vals)
|
||||
if res.last_date_to_execute_transaction:
|
||||
for rec in self.env['cm.subject.type'].search([]):
|
||||
rec.last_date_to_execute_transaction_id = True
|
||||
return res
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue