<commit_before>#
# Copyright (C) 2007-2013 by <NAME>, frePPLe bvba
#
# This library is free software; you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

from __future__ import print_function
import base64
import mimetools
import os
from datetime import datetime
try:
  from urllib2 import urlopen, HTTPError, Request
except:
  from urllib.request import urlopen, HTTPError, Request
from xml.sax.saxutils import quoteattr

from django.utils.http import urlencode

from django.db import DEFAULT_DB_ALIAS
from django.conf import settings

from freppledb.common.models import Parameter
from freppledb.execute.commands import printWelcome, logProgress, createPlan, exportPlan

import frepple


def odoo_read(db=DEFAULT_DB_ALIAS):
  '''
  This function connects to a URL, authenticates itself using HTTP basic
  authentication, and then reads data from the URL.
  The data from the source must adhere to frePPLe's official XML schema,
  as defined in the schema files bin/frepple.xsd and bin/frepple_core.xsd.
  '''
  odoo_user = Parameter.getValue("odoo.user", db)
  odoo_password = Parameter.getValue("odoo.password", db)
  odoo_db = Parameter.getValue("odoo.db", db)
  odoo_url = Parameter.getValue("odoo.url", db)
  odoo_company = Parameter.getValue("odoo.company", db)
  ok = True
  if not odoo_user:
    print("Missing or invalid odoo.user parameter")
    ok = False
  if not odoo_password:
    print("Missing or invalid parameter odoo.password")
    ok = False
  if not odoo_db:
    print("Missing or invalid parameter odoo.db")
    ok = False
  if not odoo_url:
    print("Missing or invalid parameter odoo.url")
    ok = False
  if not odoo_company:
    print("Missing or invalid parameter odoo.company")
    ok = False
  odoo_language = Parameter.getValue("odoo.language", db, 'en_US')
  if not ok:
    print("Skipping data import from odoo")
    return

  # Connect to the odoo URL to GET data
  try:
    request = Request("%s/frepple/xml/?%s" % (odoo_url, urlencode({
      'database': odoo_db, 'language': odoo_language, 'company': odoo_company
      })))
    encoded = base64.encodestring('%s:%s' % (odoo_user, odoo_password)).replace('\n', '')
    request.add_header("Authorization", "Basic %s" % encoded)
    f = urlopen(request)
  except HTTPError as e:
    print("Error connecting to odoo", e.read())
    raise e

  # Download and parse XML data
  frepple.readXMLdata(f.read(), False, False)


def odoo_write(db=DEFAULT_DB_ALIAS):
  '''
  Uploads operationplans to odoo.
    - Sends all operationplans, meeting the criteria:
      a) locked = False
         The operationplans with locked equal to true are input to the plan,
         and not output.
      b) operationplan produces into a buffer whose source field is 'odoo'.
         Only those results are of interest to odoo.
    - We upload the following info in XML form:
       - id: frePPLe generated unique identifier
       - operation
       - start
       - end
       - quantity
       - location: This is the odoo id of the location, as stored in
         buffer.location.subcategory.
       - item: This is the odoo id of the produced item and its uom_id, as
         stored in buffer.item.subcategory.
       - criticality: 0 indicates a critical operationplan, 999 indicates a
         redundant operationplan.
    - The XML file uploaded is not exactly the standard XML of frePPLe, but a
      slight variation that fits odoo better.
    - This code doesn't interprete any of the results. An odoo addon module
      will need to read the content, and take appropriate actions in odoo:
      such as creating purchase orders, manufacturing orders, work orders,
      project tasks, etc...
  '''
  odoo_user = Parameter.getValue("odoo.user", db)
  odoo_password = Parameter.getValue("odoo.password", db)
  odoo_db = Parameter.getValue("odoo.db", db)
  odoo_url = Parameter.getValue("odoo.url", db)
  odoo_company = Parameter.getValue("odoo.company", db)
  ok = True
  if not odoo_user:
    print("Missing or invalid odoo.user parameter")
    ok = False
  if not odoo_password:
    print("Missing or invalid parameter odoo.password")
    ok = False
  if not odoo_db:
    print("Missing or invalid parameter odoo.db")
    ok = False
  if not odoo_url:
    print("Missing or invalid parameter odoo.url")
    ok = False
  if not odoo_company:
    print("Missing or invalid parameter odoo.company")
    ok = False
  odoo_language = Parameter.getValue("odoo.language", db, 'en_US')
  if not ok:
    print("Skipping data export from odoo")
    return
  boundary = mimetools.choose_boundary()

  # Generator function
  # We generate output in the multipart/form-data format.
  # We send the connection parameters as well as a file with the planning
  # results in XML-format.
  def publishPlan():
    yield '--%s\r' % boundary
    yield 'Content-Disposition: form-data; name="database"\r'
    yield '\r'
    yield '%s\r' % odoo_db
    yield '--%s\r' % boundary
    yield 'Content-Disposition: form-data; name="language"\r'
    yield '\r'
    yield '%s\r' % odoo_language
    yield '--%s\r' % boundary
    yield 'Content-Disposition: form-data; name="company"\r'
    yield '\r'
    yield '%s\r' % odoo_company
    yield '--%s\r' % boundary
    yield 'Content-Disposition: file; name="frePPLe plan"; filename="frepple_plan.xml"\r'
    yield 'Content-Type: application/xml\r'
    yield '\r'
    yield '<?xml version="1.0" encoding="UTF-8" ?>'
    yield '<plan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
    # Export relevant operationplans
    yield '<operationplans>'
    for i in frepple.operationplans():
      b = None
      for j in i.flowplans:
        if j.quantity > 0:
          b = j.flow.buffer
      if not b or b.source != 'odoo' or i.locked:
        continue
      yield '<operationplan id="%s" operation=%s start="%s" end="%s" quantity="%s" location=%s item=%s criticality="%s"/>' % (
        i.id, quoteattr(i.operation.name),
        i.start, i.end, i.quantity,
        quoteattr(b.location.subcategory), quoteattr(b.item.subcategory),
        i.criticality
        )
    yield '</operationplans>'
    yield '</plan>'
    yield '--%s--\r' % boundary
    yield '\r'

  # Connect to the odoo URL to POST data
  try:
    req = Request("%s/frepple/xml/" % odoo_url.encode('ascii'))
    body = '\n'.join(publishPlan()).encode('utf-8')
    size = len(body)
    encoded = base64.encodestring('%s:%s' % (odoo_user, odoo_password)).replace('\n', '')
    req.add_header("Authorization", "Basic %s" % encoded)
    req.add_header("Content-Type", 'multipart/form-data; boundary=%s' % boundary)
    req.add_header('Content-length', size)
    req.add_data(body)

    # Posting the data
    print("Uploading %d bytes of planning results to odoo" % size)
    req.get_data()

    # Display the server response, which can contain error messages
    print("Odoo response:")
    for i in urlopen(req):
      print(i, end="")<commit_msg>odoo connector: exporting criticality as an integer<commit_after>#
# Copyright (C) 2007-2013 by <NAME>, frePPLe bvba
#
# This library is free software; you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

from __future__ import print_function
import base64
import mimetools
import os
from datetime import datetime
try:
  from urllib2 import urlopen, HTTPError, Request
except:
  from urllib.request import urlopen, HTTPError, Request
from xml.sax.saxutils import quoteattr

from django.utils.http import urlencode

from django.db import DEFAULT_DB_ALIAS
from django.conf import settings

from freppledb.common.models import Parameter
from freppledb.execute.commands import printWelcome, logProgress, createPlan, exportPlan

import frepple


def odoo_read(db=DEFAULT_DB_ALIAS):
  '''
  This function connects to a URL, authenticates itself using HTTP basic
  authentication, and then reads data from the URL.
  The data from the source must adhere to frePPLe's official XML schema,
  as defined in the schema files bin/frepple.xsd and bin/frepple_core.xsd.
  '''
  odoo_user = Parameter.getValue("odoo.user", db)
  odoo_password = Parameter.getValue("odoo.password", db)
  odoo_db = Parameter.getValue("odoo.db", db)
  odoo_url = Parameter.getValue("odoo.url", db)
  odoo_company = Parameter.getValue("odoo.company", db)
  ok = True
  if not odoo_user:
    print("Missing or invalid odoo.user parameter")
    ok = False
  if not odoo_password:
    print("Missing or invalid parameter odoo.password")
    ok = False
  if not odoo_db:
    print("Missing or invalid parameter odoo.db")
    ok = False
  if not odoo_url:
    print("Missing or invalid parameter odoo.url")
    ok = False
  if not odoo_company:
    print("Missing or invalid parameter odoo.company")
    ok = False
  odoo_language = Parameter.getValue("odoo.language", db, 'en_US')
  if not ok:
    print("Skipping data import from odoo")
    return

  # Connect to the odoo URL to GET data
  try:
    request = Request("%s/frepple/xml/?%s" % (odoo_url, urlencode({
      'database': odoo_db, 'language': odoo_language, 'company': odoo_company
      })))
    encoded = base64.encodestring('%s:%s' % (odoo_user, odoo_password)).replace('\n', '')
    request.add_header("Authorization", "Basic %s" % encoded)
    f = urlopen(request)
  except HTTPError as e:
    print("Error connecting to odoo", e.read())
    raise e

  # Download and parse XML data
  frepple.readXMLdata(f.read(), False, False)


def odoo_write(db=DEFAULT_DB_ALIAS):
  '''
  Uploads operationplans to odoo.
    - Sends all operationplans, meeting the criteria:
      a) locked = False
         The operationplans with locked equal to true are input to the plan,
         and not output.
      b) operationplan produces into a buffer whose source field is 'odoo'.
         Only those results are of interest to odoo.
    - We upload the following info in XML form:
       - id: frePPLe generated unique identifier
       - operation
       - start
       - end
       - quantity
       - location: This is the odoo id of the location, as stored in
         buffer.location.subcategory.
       - item: This is the odoo id of the produced item and its uom_id, as
         stored in buffer.item.subcategory.
       - criticality: 0 indicates a critical operationplan, 999 indicates a
         redundant operationplan.
    - The XML file uploaded is not exactly the standard XML of frePPLe, but a
      slight variation that fits odoo better.
    - This code doesn't interprete any of the results. An odoo addon module
      will need to read the content, and take appropriate actions in odoo:
      such as creating purchase orders, manufacturing orders, work orders,
      project tasks, etc...
  '''
  odoo_user = Parameter.getValue("odoo.user", db)
  odoo_password = Parameter.getValue("odoo.password", db)
  odoo_db = Parameter.getValue("odoo.db", db)
  odoo_url = Parameter.getValue("odoo.url", db)
  odoo_company = Parameter.getValue("odoo.company", db)
  ok = True
  if not odoo_user:
    print("Missing or invalid odoo.user parameter")
    ok = False
  if not odoo_password:
    print("Missing or invalid parameter odoo.password")
    ok = False
  if not odoo_db:
    print("Missing or invalid parameter odoo.db")
    ok = False
  if not odoo_url:
    print("Missing or invalid parameter odoo.url")
    ok = False
  if not odoo_company:
    print("Missing or invalid parameter odoo.company")
    ok = False
  odoo_language = Parameter.getValue("odoo.language", db, 'en_US')
  if not ok:
    print("Skipping data export from odoo")
    return
  boundary = mimetools.choose_boundary()

  # Generator function
  # We generate output in the multipart/form-data format.
  # We send the connection parameters as well as a file with the planning
  # results in XML-format.
  def publishPlan():
    yield '--%s\r' % boundary
    yield 'Content-Disposition: form-data; name="database"\r'
    yield '\r'
    yield '%s\r' % odoo_db
    yield '--%s\r' % boundary
    yield 'Content-Disposition: form-data; name="language"\r'
    yield '\r'
    yield '%s\r' % odoo_language
    yield '--%s\r' % boundary
    yield 'Content-Disposition: form-data; name="company"\r'
    yield '\r'
    yield '%s\r' % odoo_company
    yield '--%s\r' % boundary
    yield 'Content-Disposition: file; name="frePPLe plan"; filename="frepple_plan.xml"\r'
    yield 'Content-Type: application/xml\r'
    yield '\r'
    yield '<?xml version="1.0" encoding="UTF-8" ?>'
    yield '<plan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
    # Export relevant operationplans
    yield '<operationplans>'
    for i in frepple.operationplans():
      b = None
      for j in i.flowplans:
        if j.quantity > 0:
          b = j.flow.buffer
      if not b or b.source != 'odoo' or i.locked:
        continue
      yield '<operationplan id="%s" operation=%s start="%s" end="%s" quantity="%s" location=%s item=%s criticality="%d"/>' % (
        i.id, quoteattr(i.operation.name),
        i.start, i.end, i.quantity,
        quoteattr(b.location.subcategory), quoteattr(b.item.subcategory),
        int(i.criticality)
        )
    yield '</operationplans>'
    yield '</plan>'
    yield '--%s--\r' % boundary
    yield '\r'

  # Connect to the odoo URL to POST data
  try:
    req = Request("%s/frepple/xml/" % odoo_url.encode('ascii'))
    body = '\n'.join(publishPlan()).encode('utf-8')
    size = len(body)
    encoded = base64.encodestring('%s:%s' % (odoo_user, odoo_password)).replace('\n', '')
    req.add_header("Authorization", "Basic %s" % encoded)
    req.add_header("Content-Type", 'multipart/form-data; boundary=%s' % boundary)
    req.add_header('Content-length', size)
    req.add_data(body)

    # Posting the data
    print("Uploading %d bytes of planning results to odoo" % size)
    req.get_data()

    # Display the server response, which can contain error messages
    print("Odoo response:")
    for i in urlopen(req):
      print(i, end="")
{'fraction_non_alphanumeric': 0.10584160394324918, 'fraction_numerical': 0.00399653633517618, 'mean_word_length': 3.2983109075293444, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 2, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 14}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5383286', 'n_tokens_mistral': 4775, 'n_tokens_neox': 4693, 'n_words': 1571}