Commit eb41ec18 by François C.

Ajout module Commande DIAPAR EDI

parent bfd74d75
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
======================
EDI Purchase DIAPAR
======================
Features
--------
This module allows Diapar EDI Purchase Orders.
Credits
=======
Yassine TEIMI <yteimi01@gmail.com>
Simon Mas <simon.mas@druidoo.io>
Funders
-------
The development of this module has been financially supported by:
* La Louve (https://cooplalouve.fr/)
* Les Grains de Sel (http://lesgrainsdesel.fr)
# -*- coding: utf-8 -*-
# Copyright (C) 2016-Today: Druidoo (<http://www.druidoo.io/>)
# @author: Druidoo
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html
from . import models
# -*- coding: utf-8 -*-
# Copyright (C) 2016-2021: Druidoo (<http://www.druidoo.io/>)
# Copyright (C) 2021-today: Cooperatic (<http://cooperatic.fr/>)
# @author: Druidoo
# @author: Cooperatic
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html
{
'name': 'EDI Purchase DIAPAR',
'version': '9.0.1.2',
'category': 'Custom',
'author': 'Druidoo / Cooperatic',
'website': 'http://www.druidoo.io , https://cooperatic.fr',
'license': 'AGPL-3',
'depends': [
'product',
'coop_purchase',
'coop_membership'
],
'data': [
'data/ir_config_parameter.xml',
'views/actions.xml',
'views/menus.xml',
'views/purchase_edi_log_view.xml',
'views/res_partner_view.xml',
'security/ir_module_category.xml',
'security/res_groups.xml',
'security/ir.model.access.csv',
],
}
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data noupdate="1">
<record id="edi_folder_path" model="ir.config_parameter">
<field name="key">edi.local_folder_path</field>
<field name="value">/tmp/</field>
</record>
<record id="edi_diapar_ftp_host" model="ir.config_parameter">
<field name="key">edi.diapar.ftp_host</field>
<field name="value"> </field>
</record>
<record id="edi_diapar_ftp_port" model="ir.config_parameter">
<field name="key">edi.diapar.ftp_port</field>
<field name="value">21</field>
</record>
<record id="edi_diapar_ftp_login" model="ir.config_parameter">
<field name="key">edi.diapar.ftp_login</field>
<field name="value"> </field>
</record>
<record id="edi_diapar_ftp_pwd" model="ir.config_parameter">
<field name="key">edi.diapar.ftp_pwd</field>
<field name="value"> </field>
</record>
<record id="edi_diapar_customer_code" model="ir.config_parameter">
<field name="key">edi.diapar.customer_code</field>
<field name="value"> </field>
</record>
<record id="edi_diapar_vrp_code" model="ir.config_parameter">
<field name="key">edi.diapar.vrp_code</field>
<field name="value">03</field>
</record>
</data>
</odoo>
# -*- coding: utf-8 -*-
# Copyright (C) 2016-Today: Druidoo (<http://www.druidoo.io/>)
# @author: Druidoo
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html
from . import product
from . import purchase
from . import edi_config_system
from . import purchase_edi_log
from . import res_partner
# -*- coding: utf-8 -*-
# Copyright (C) 2016-2021: Druidoo (<http://www.druidoo.io/>)
# Copyright (C) 2021-today: Cooperatic (<http://cooperatic.fr/>)
# @author: Druidoo
# @author: Cooperatic
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html
import time
import fnmatch
import zipfile
import logging
import os
from dateutil import parser
import datetime
from openerp import models, api, fields, tools, _
from openerp.exceptions import ValidationError
_logger = logging.getLogger(__name__)
try:
from ftplib import FTP
except ImportError:
_logger.warning(
"Cannot import 'ftplib' Python Librairy. 'edi_purchase_*'"
" module will not work properly.")
def get_datenow_format_for_file():
now = time.strftime("%Y-%m-%d %H:%M:%S")
date = now.split(' ')[0].replace('-', '')
hour = now.split(' ')[1].replace(':', '')
return date, hour
def get_text_file_pattern():
day, hour = get_datenow_format_for_file()
return 'LD' + day + 'H' + hour + '.C99'
class DiaparEdiConfigSystem(models.Model):
_name = 'diapar.edi.config.system'
_auto = False
# po_text_file_pattern = get_text_file_pattern()
constant_file_start = 'HDIAPAR '
constant_file_end = '*DIAPAR*DIAPAR'
csv_relative_in_path = '/Reception'
csv_relative_out_path = '/Envoi'
@api.model
def get_text_file_pattern():
day, hour = get_datenow_format_for_file()
return 'LD' + day + 'H' + hour + '.C99'
@api.one
@api.constrains('ftp_port')
def _check_ftp_port(self):
if not self.ftp_port.isdigit():
raise ValidationError(_("FTP port must be numeric!"))
@api.model
def ftp_connection_open(self):
"""Return a new FTP connection with found parameters."""
config_obj = self.env['ir.config_parameter']
login = config_obj.get_param('edi.diapar.ftp_login')
host = config_obj.get_param('edi.diapar.ftp_host')
port = config_obj.get_param('edi.diapar.ftp_port')
_logger.info("Trying to connect to ftp://%s@%s:%s" % (
login, host, port))
try:
ftp = FTP()
ftp.connect(host)
if login:
ftp.login(
login,
config_obj.get_param('edi.diapar.ftp_pwd'))
else:
ftp.login()
return ftp
except Exception, e:
raise ValidationError(_("Error when opening FTP connection:\n %s") % tools.ustr(e))
@api.model
def ftp_connection_close(self, ftp):
try:
ftp.quit()
except Exception, e:
raise ValidationError(_("Error when closing FTP connection:\n %s") % tools.ustr(e))
@api.model
def ftp_connection_push_order_file(self, ftp, distant_folder_path, local_folder_path,
pattern, lines, encoding='utf-8'):
try:
if lines:
# Generate temporary file
f_name = datetime.datetime.now().strftime(pattern)
local_path = os.path.join(local_folder_path, f_name)
distant_path = os.path.join(distant_folder_path, f_name)
f = open(local_path, 'w')
for line in lines:
raw_text = line
f.write(raw_text.encode(encoding, errors='ignore'))
f.close()
# Send File by FTP
f = open(local_path, 'r')
ftp.storbinary('STOR ' + distant_path, f)
f.close()
# Delete temporary file
# os.remove(local_path)
except Exception, e:
raise ValidationError(_("Error when pushing order file:\n %s") % tools.ustr(e))
@api.model
def get_datetime_format_ddmmyyyy(self, date):
do_date = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
return "%02d%02d%s" % (do_date.day, do_date.month, str(do_date.year)[2:])
@api.model
def get_date_format_yyyymmdd(self, date):
"""
Transform a string date to datetime and format it to standard odoo date format
"""
return datetime.datetime.strptime(date, "%y%m%d").strftime('%Y-%m-%d')\
@api.model
def get_date_format_ble_yyyymmdd(self, date):
"""
Transform a string date (specific to delivery order interface format) to datetime object and format it to standard odoo date format
"""
return datetime.datetime.strptime(date, "%Y%m%d").strftime('%Y-%m-%d')
@api.model
def insert_separator(self, string, index, separator):
"""
This method is to insert a separator inside string on a certain position
"""
return string[:index] + separator + string[index:]
@api.model
def _fix_lenght(self, value, lenght, mode='float', replace='', position='before'):
"""
Mode = string/integer
replace ==> ' ' or '0'
position ==> before / after
"""
value = str(value)
if mode == 'float':
value = value.split('.')[0]
if position == 'before':
value = ''.join([replace for i in range(lenght - len(value))]) + value
else:
value += ''.join([replace for i in range(lenght - len(value))])
return value[0:lenght]
# -*- coding: utf-8 -*-
# Copyright (C) 2016-Today: Druidoo (<http://www.druidoo.net/>)
# @author: Druidoo
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html
import datetime # Used when eval python codes !!
from openerp import models, api, fields, tools, _
from openerp.exceptions import ValidationError
import logging
_logger = logging.getLogger(__name__)
class ProductProduct(models.Model):
_inherit = 'product.product'
@api.multi
def _get_supplier_code_or_ean(self, seller_id):
"""
"""
self.ensure_one()
code, origin_code = '', ''
seller_line = self.seller_ids.filtered(lambda l: l.name==seller_id and l.product_code)
if seller_line and seller_line[0].product_code:
code = seller_line[0].product_code
origin_code = 'supplier'
elif self.barcode:
code = self.barcode
origin_code = 'barcode'
if not code:
raise ValidationError(_("No code for this product %s!") % self.name)
return code, origin_code
# -*- coding: utf-8 -*-
# Copyright (C) 2016-2021: Druidoo (<http://www.druidoo.net/>)
# Copyright (C) 2021-today: Cooperatic (<http://cooperatic.fr/>)
# @author: Druidoo
# @author: Cooperatic
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html
from openerp import models, api, fields, _
from openerp.exceptions import ValidationError
import time
import logging
_logger = logging.getLogger(__name__)
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
date_planned = fields.Datetime(string='Scheduled Date', compute='_compute_date_planned', required=True, index=True,
oldname='minimum_planned_date', store=True, copy=True)
@api.multi
def _consolidate_products(self):
"""
Consolidate order lines by product.
Raise if Tax or price different.
@return: dict {product_id(record):[code_or_ean, qty, nb_of_packages price, taxes(records)]}
"""
self.ensure_one()
if not self.order_line:
raise ValidationError(_("No lines in this order %s!") % self.name)
lines = {}
for line in self.order_line:
if line.product_id in lines:
if line.taxes_id != lines[line.product_id]['taxes_id']:
raise ValidationError(_("Check taxes for lines with product %s!") % line.product_id.name)
if line.price_unit != lines[line.product_id]['price_unit']:
raise ValidationError(_("Check price for lines with product %s!") % line.product_id.name)
lines[line.product_id]['quantity'] += line.product_qty
else:
code, origin_code = line.product_id._get_supplier_code_or_ean(line.partner_id)
values = {
'code': code,
'origin_code': origin_code,
'quantity': line.product_qty,
'package_to_order': line.product_qty_package,
'price_unit': line.price_unit,
'taxes_id': line.taxes_id
}
lines.update({line.product_id: values})
return lines
@api.multi
def _get_data(self, order_lines):
"""
Order lines are parsed to generate core date (Product and Nb of packages)
"""
self.ensure_one()
data = """"""
try:
for key, val in order_lines.items():
field_name = 'E'
if val['origin_code'] == 'supplier':
field_name = 'D'
data += field_name + val['code'] + str(int(val['package_to_order'])).zfill(3)
except Exception as e:
_logger.error("Error _get_data (EDI PurchaseOrder) : %s", str(e))
return data
@api.multi
def _prepare_data_lines(self, lines, edi):
"""
Data lines to send
"""
config_obj = self.env['ir.config_parameter']
self.ensure_one()
data = None
compact_data = self._get_data(lines)
if len(compact_data) > 0:
delivry_date_code = 'C' + edi.get_datetime_format_ddmmyyyy(self.date_planned)
data = """%sA%sB%s%s%s""" % (edi.constant_file_start,
config_obj.get_param('edi.diapar.vrp_code'),
config_obj.get_param('edi.diapar.customer_code'),
delivry_date_code + compact_data,
edi.constant_file_end)
return data
@api.multi
def _process_send_ftp(self):
"""
Process Send FTP
"""
self.ensure_one()
ecs_obj = self.env['diapar.edi.config.system']
config_obj = self.env['ir.config_parameter']
# Consolidated lines
lines = self._consolidate_products()
now = time.strftime("%Y-%m-%d %H:%M:%S")
day = now.split(' ')[0].replace('-', '')
hour = now.split(' ')[1].replace(':', '')
# Prepare data file
data_lines = self._prepare_data_lines(lines, ecs_obj)
# Params
filename = 'LD' + day + 'H' + hour + '.C99'
distant_folder_path = ecs_obj.csv_relative_in_path
local_folder_path = config_obj.get_param('edi.local_folder_path')
has_been_sent = False
try:
# Open FTP
ftp = ecs_obj.ftp_connection_open()
# Send
ecs_obj.ftp_connection_push_order_file(ftp,
distant_folder_path,
local_folder_path,
filename,
data_lines,
encoding='utf-8')
# Close FTP
ecs_obj.ftp_connection_close(ftp)
has_been_sent = True
except Exception as e:
_logger.error("Error while sending EDI %s : %s", filename, str(e))
# Log
self.env['purchase.edi.log'].create_log_history(_('Orders interface'), sent=has_been_sent)
_logger.info("EDI PurchaseOrder filename : %s", filename)
return True
@api.multi
def button_confirm(self):
"""
Override: Send FTP.
"""
res = super(PurchaseOrder, self).button_confirm()
for order in self.filtered(lambda l: l.partner_id.is_edi):
order._process_send_ftp()
return res
# -*- coding: utf-8 -*-
# Copyright (C) 2016-2021: Druidoo (<http://www.druidoo.io/>)
# Copyright (C) 2021-Today: Cooperatic (<http://cooperatic.fr/>)
# @author: Druidoo
# @author: Cooperatic
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html
from openerp import models, api, fields
class PurchaseEdiLog(models.Model):
_name = 'purchase.edi.log'
_inherit = 'ir.needaction_mixin'
_order = 'log_date desc, id desc'
log_date = fields.Datetime(string="Log Date", required=True)
user_id = fields.Many2one(comodel_name="res.users", string="User")
name = fields.Char(string="Interface", required=True)
sent = fields.Boolean(string="Successfull ?")
# View Section
def _needaction_count(self, cr, uid, domain=None, context=None):
return len(self.search(cr, uid, [('sent', '=', False)], context=context))
@api.model
def create_log_history(self, supplier_interface, edi_system=None, sent=False):
return self.create({'user_id': self.env.user.id,
'log_date': fields.datetime.now(),
'name': supplier_interface,
# 'edi_system_id': edi_system,
'sent': sent})
# -*- coding: utf-8 -*-
# Copyright (C) 2016-2021: Druidoo (<http://www.druidoo.io/>)
# Copyright (C) 2021-Today: Cooperatic (<http://cooperatic.fr/>)
# @author: Druidoo
# @author: Cooperatic
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html
from openerp import models, fields
class ResPartner(models.Model):
_inherit = 'res.partner'
is_edi = fields.Boolean(string="Is an EDI supplier")
is_prices_interface = fields.Boolean(string="Supports prices interface")
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_model_diapar_edi_config_system_all,access_model_diapar_edi_config_system_all,model_diapar_edi_config_system,,1,0,0,0
access_model_diapar_edi_config_system_manager,access_model_diapar_edi_config_system_manager,model_diapar_edi_config_system,coop_edi_purchase_diapar.group_manager,1,1,1,1
,,,,,,,
access_model_purchase_edi_log_all,access_model_purchase_edi_log_all,model_purchase_edi_log,,1,1,1,0
access_model_purchase_edi_log_manager,access_model_purchase_edi_log_manager,model_purchase_edi_log,coop_edi_purchase_diapar.group_manager,1,1,1,1
<?xml version="1.0"?>
<odoo>
<record model="ir.module.category" id="category_supplier_edi">
<field name="name">Electronic data interchange</field>
</record>
</odoo>
<?xml version="1.0"?>
<odoo>
<record model="res.groups" id="group_user">
<field name="name">EDI User</field>
<field name="category_id" ref="category_supplier_edi" />
</record>
<record model="res.groups" id="group_manager">
<field name="name">EDI Manager</field>
<field name="implied_ids" eval="[(6, False, [ref('group_user')])]" />
<field name="category_id" ref="category_supplier_edi" />
</record>
</odoo>
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="action_purchase_edi_logs" model="ir.actions.act_window">
<field name="name">Logs</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">purchase.edi.log</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<menuitem id="menu_edi_config_root"
name="EDI Purchase"
parent="purchase.menu_purchase_config" sequence="35"/>
<menuitem id="menu_purchase_edi_logs"
parent="menu_edi_config_root" sequence="2"
action="action_purchase_edi_logs"/>
</data>
</odoo>
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="view_purchase_edi_log_tree" model="ir.ui.view">
<field name="model">purchase.edi.log</field>
<field name="arch" type="xml">
<tree string="EDI Log" colors="gray:sent == True;">
<field name="log_date"/>
<field name="sent"/>
<field name="name"/>
</tree>
</field>
</record>
<record id="view_purchase_edi_log_form" model="ir.ui.view">
<field name="model">purchase.edi.log</field>
<field name="arch" type="xml">
<form>
<header/>
<sheet>
<group>
<group>
<field name="log_date"/>
<field name="sent"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_partner_form_edi" model="ir.ui.view">
<field name="name">res.partner.edi</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="coop_membership.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//form/sheet/notebook/page[@name='sales_purchases']/group[@name='container_row_2']/group[@name='purchase']/field[@name='supplier']" position="after">
<field name="is_edi"/>
</xpath>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment