Skip to content

/ Zope / gocept svn checkins / Archive / 2008 / 2008-10 / SVN: r6801 - in gocept.collmex/trunk: . src src/gocept src/gocept/collmex

[ << ] [ >> ]

[ SVN: r6795 - gocept.ooo2html/trunk / Christian ... ] [ SVN: r6835 - in gocept.infrastructure/testing: . ... ]

SVN: r6801 - in gocept.collmex/trunk: . src src/gocept src/gocept/collmex
Wolfgang Schnerring <ws(at)gocept.com>
2008-10-13 20:44:38 [ FULL ]
Author: wosc
Date: Mon Oct 13 20:44:36 2008
New Revision: 6801

Log:
initial import, based on gocept.accounting r13270


Added:
   gocept.collmex/trunk/
   gocept.collmex/trunk/CHANGES.txt
   gocept.collmex/trunk/README.txt
   gocept.collmex/trunk/bootstrap.py
   gocept.collmex/trunk/buildout.cfg
   gocept.collmex/trunk/setup.py
   gocept.collmex/trunk/src/
   gocept.collmex/trunk/src/gocept/
   gocept.collmex/trunk/src/gocept/__init__.py
   gocept.collmex/trunk/src/gocept/collmex/
   gocept.collmex/trunk/src/gocept/collmex/README.txt
   gocept.collmex/trunk/src/gocept/collmex/__init__.py
   gocept.collmex/trunk/src/gocept/collmex/collmex.py
   gocept.collmex/trunk/src/gocept/collmex/interfaces.py
   gocept.collmex/trunk/src/gocept/collmex/testing.py
   gocept.collmex/trunk/src/gocept/collmex/tests.py
   gocept.collmex/trunk/src/gocept/collmex/utils.py

Added: gocept.collmex/trunk/CHANGES.txt
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/CHANGES.txt	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,3 (at)(at)
+0.1 (unreleased)
+----------------
+

Added: gocept.collmex/trunk/README.txt
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/README.txt	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,5 (at)(at)
+==============
+gocept.collmex
+==============
+
+A Python binding for the import/export API of Collmex <http://www.collmex.de>.

Added: gocept.collmex/trunk/bootstrap.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/bootstrap.py	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,52 (at)(at)
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 1139 2008-09-01 11:21:37Z czagrodnick $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)

Added: gocept.collmex/trunk/buildout.cfg
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/buildout.cfg	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,12 (at)(at)
+[buildout]
+develop = .
+extends = local.cfg
+parts = test
+find-links = http://uter.gocept.com/mirror
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = gocept.collmex[test]
+environment = test-environment
+
+[test-environment]

Added: gocept.collmex/trunk/setup.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/setup.py	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,36 (at)(at)
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+
+import os.path
+from setuptools import setup, find_packages
+
+
+setup(
+    name='gocept.collmex',
+    version='0.1dev',
+    author='gocept',
+    author_email='mail(at)gocept.com',
+    description='A Python API for Collmex import/export',
+    long_description = (
+        open('README.txt').read() +
+        '\n\n' +
+        open(os.path.join('src', 'gocept', 'collmex', 'README.txt')).read() +
+        '\n\n' +
+        open('CHANGES.txt').read()),
+    packages=find_packages('src'),
+    package_dir = {'': 'src'},
+    include_package_data=True,
+    zip_safe=False,
+    license='ZPL 2.1',
+    namespace_packages=['gocept'],
+    install_requires=[
+        'setuptools',
+        'transaction',
+        'zope.interface',
+        ],
+    extras_require=dict(
+        test=[
+            'zope.testing',
+            'zope.testbrowser>=3.4.3',
+            ]),
+)

Added: gocept.collmex/trunk/src/gocept/__init__.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/src/gocept/__init__.py	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,8 (at)(at)
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+#namespace package boilerplate
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError, e:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)

Added: gocept.collmex/trunk/src/gocept/collmex/README.txt
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/src/gocept/collmex/README.txt	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,52 (at)(at)
+===========
+Collmex API
+===========
+
+Collmex provides a POST- and CSV-based API, which is encapsulated into a
utility
+that provides methods for the various CSV record types.
+API documentation is available at <http://www.collmex.de/cgi-bin/cgi.exe?1005,1,help,api>.
+
+First we need to clean up the Collmex environment:
+>>> import gocept.collmex.testing
+>>> gocept.collmex.testing.cleanup_collmex()
+
+Invalid login information raises an exception:
+
+>>> import os
+>>> import gocept.collmex.collmex
+>>> collmex = gocept.collmex.collmex.Collmex(
+...     os.environ['collmex_customer'], os.environ['collmex_company'],
+...     os.environ['collmex_username'], 'invalid')
+>>> collmex.get_invoices(customer_id='10000')
+Traceback (most recent call last):
+APIError: ('204008', 'Fehler in Zeile 1: Benutzer oder Kennwort nicht
korrekt')
+
+
+Invoices
+========
+
+Invoices can be looked up again, however, the invoice was only registered for
+addition and the transaction needs to be committed first:
+
+>>> import datetime
+>>> collmex = gocept.collmex.collmex.Collmex(
+...     os.environ['collmex_customer'], os.environ['collmex_company'],
+...     os.environ['collmex_username'], os.environ['collmex_password'])
+>>> start_date = datetime.datetime.now()
+>>> item = gocept.collmex.collmex.InvoiceItem()
+>>> item['Kunden-Nr'] = '10000'
+>>> item['Rechnungsnummer'] = 100000
+>>> item['Menge'] = 3
+>>> item['Produktnummer'] = 'TRAFFIC'
+>>> item['Rechnungstext'] = 'item text'
+>>> item['Positionstyp'] = 0
+>>> collmex.create_invoice([item])
+>>> collmex.get_invoices(customer_id='10000', start_date=start_date)
+[]
+
+After committing, the invoice is found:
+
+>>> import transaction
+>>> transaction.commit()
+>>> collmex.get_invoices(customer_id='10000',
start_date=start_date)[0]['Rechnungstext']
+'item text'

Added: gocept.collmex/trunk/src/gocept/collmex/__init__.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/src/gocept/collmex/__init__.py	Mon Oct 13 20:44:36
2008
(at)(at) -0,0 +1,2 (at)(at)
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt

Added: gocept.collmex/trunk/src/gocept/collmex/collmex.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/src/gocept/collmex/collmex.py	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,258 (at)(at)
+# -*- coding: utf-8 -*-
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+
+import StringIO
+import UserDict
+import csv
+import gocept.collmex.interfaces
+import gocept.collmex.utils
+import threading
+import transaction
+import transaction.interfaces
+import urllib2
+import zope.interface
+
+
+class CollmexDialect(csv.Dialect):
+    quoting = csv.QUOTE_ALL
+    delimiter = ';'
+    quotechar = '"'
+    lineterminator = '\r\n'
+    doublequote = True
+    skipinitialspace = True
+
+
+class APIError(Exception):
+    pass
+
+
+class CollmexDataManager(object):
+    zope.interface.implements(transaction.interfaces.IDataManager)
+
+    def __init__(self, utility):
+        self.utility = utility
+        self._reset()
+
+    def _reset(self):
+        self.data = StringIO.StringIO()
+        self._joined = False
+        self._transaction = None
+
+    def register_data(self, data):
+        """Registers one or more CSV lines for writing."""
+        self.data.write(data)
+        if not self._joined:
+            transaction.get().join(self)
+            self._joined = True
+
+    def abort(self, transaction):
+        if self._transaction is not None:
+            # No abort during TPC.
+            return
+        self._reset()
+
+    def tpc_begin(self, transaction):
+        self._transaction = transaction
+
+    def commit(self, transaction):
+        assert transaction is self._transaction
+        # We need to do our work in tpc_vote as we're a single-phase-only data
manager.
+        pass
+
+    def tpc_vote(self, transaction):
+        assert transaction is self._transaction
+        self.utility._post(self.data.getvalue())
+        self.voted = True
+
+    def tpc_abort(self, transaction):
+        assert transaction is self._transaction
+        if self.voted:
+            raise Exception('Single phase data manager: cannot abort after
vote')
+        self._reset()
+
+    def tpc_finish(self, transaction):
+        assert transaction is self._transaction
+        self._reset()
+
+    def sortKey(self):
+        # XXX make very small or add single-phase datamanager integration to
the transaction module.
+        return None
+
+
+class Collmex(object):
+    zope.interface.implements(gocept.collmex.interfaces.ICollmex)
+
+    # XXX should go on CollmexDialect but the csv module's magic prevents it
+    NULL = '(NULL)'
+
+    def __init__(self, customer_id, company_id, username, password):
+        self.customer_id = customer_id
+        self.company_id = company_id
+        self.username = username
+        self.password = password
+
+        # Store thread-local (actually: transaction-local) information
+        self._local = threading.local()
+
+    (at)property
+    def connection(self):
+        connection = getattr(self._local, 'connection', None)
+        if connection is None:
+            connection = self._local.connection = CollmexDataManager(self)
+        return connection
+
+    def create_invoice(self, items):
+        data = StringIO.StringIO()
+        writer = csv.writer(data, dialect=CollmexDialect)
+        for item in items:
+            item['Firma Nr'] = self.company_id
+            writer.writerow(list(item))
+        self.connection.register_data(data.getvalue())
+
+    def get_invoices(self, invoice_id=NULL, customer_id=NULL,
+                     start_date=NULL, end_date=NULL):
+        data = StringIO.StringIO()
+        writer = csv.writer(data, dialect=CollmexDialect)
+        writer.writerow(['INVOICE_GET', invoice_id, self.company_id,
customer_id,
+                         date_to_collmex(start_date),
date_to_collmex(end_date),
+                         0, 0, 0, 'gocept.collmex'])
+        lines = self._post(data.getvalue())
+        return [InvoiceItem(line) for line in lines]
+
+    def _post(self, data):
+        data = 'LOGIN;%s;%s\n' % (self.username, self.password) + data
+
+        content_type, body = gocept.collmex.utils.encode_multipart_formdata(
+            [], [('fileName', 'api.csv', data)])
+
+        request = urllib2.Request('https://www.collmex.de/cgi-bin/cgi.exe?%s,0,data_exchange'
+                                  % self.customer_id, body)
+        request.add_header('Content-type', content_type)
+        result = urllib2.urlopen(request)
+        lines = list(csv.reader(result, dialect=CollmexDialect))
+        response = lines.pop()
+        record_type, message_type, message_id, message_text = response
+        if record_type != 'MESSAGE':
+            raise TypeError('API returned invalid response record: %r' %
response)
+        if message_type != 'S':
+            raise APIError(message_id, message_text)
+        return lines
+
+
+def date_to_collmex(date):
+    if date == Collmex.NULL:
+        return date
+    else:
+        return date.strftime('%Y%m%d')
+
+
+class InvoiceItem(UserDict.UserDict):
+    zope.interface.implements(gocept.collmex.interfaces.IInvoiceItem)
+
+    def __init__(self, row=[]):
+        UserDict.UserDict.__init__(self)
+
+        self['Satzart'] = 'CMXINV'
+        self['Rechnungsart'] = 0 # type invoice
+
+        for i in range(len(row)):
+            if row[i] == '':
+                row[i] = None
+            self[self.fields[i]] = row[i]
+
+    def __iter__(self):
+        result = []
+        for field in self.fields:
+            if field in self:
+                value = self[field]
+                if isinstance(value, unicode):
+                    value = value.encode('iso-8859-1')
+                yield value
+            else:
+                yield Collmex.NULL
+
+    fields = [
+        'Satzart',
+        'Rechnungsnummer',
+        'Position',
+        'Rechnungsart',
+        'Firma Nr',
+        'Auftrag Nr',
+        'Kunden-Nr',
+        'Anrede',
+        'Titel',
+        'Vorname',
+        'Name',
+        'Firma',
+        'Abteilung',
+        'Strasse',
+        'PLZ',
+        'Ort',
+        'Land',
+        'Telefon',
+        'Telefon2',
+        'Telefax',
+        'E-Mail',
+        'Kontonr',
+        'Blz',
+        'Abweichender Kontoinhaber',
+        'IBAN',
+        'BIC',
+        'Bank',
+        'USt.IdNr',
+        'Privatperson',
+        'Rechnungsdatum',
+        'Preisdatum',
+        'Zahlungsbedingung',
+        'Währung',
+        'Preisgruppe',
+        'Rabattgruppe',
+        'Schluss-Rabatt',
+        'Rabattgrund',
+        'Rechnungstext',
+        'Schlusstext',
+        'Internes Memo',
+        'Gelöscht',
+        'Sprache',
+        'Bearbeiter',
+        'Reserviert',
+        'Reserviert',
+        'Reserviert',
+        'Reserviert',
+        'Reserviert',
+        'Versandart',
+        'Versandkosten',
+        'Nachnahmegebühr',
+        'Lieferdatum',
+        'Lieferbedingung',
+        'Lieferbedingung Zusatz',
+        'Anrede Lieferung',
+        'Titel Lieferung',
+        'Vorname Lieferung',
+        'Name Lieferung',
+        'Firma Lieferung',
+        'Abteilung Lieferung',
+        'Strasse Lieferung',
+        'PLZ Lieferung',
+        'Ort Lieferung',
+        'Land Lieferung',
+        'Telefon Lieferung',
+        'Telefon2 Lieferung',
+        'Telefax Lieferung',
+        'E-Mail Lieferung',
+        'Positionstyp',
+        'Produktnummer',
+        'Produktbeschreibung',
+        'Mengeneinheit',
+        'Menge',
+        'Einzelpreis',
+        'Preismenge',
+        'Positionsrabatt',
+        'Positionswert',
+        'Produktart',
+        'Steuerklassifikation',
+        'Steuer auch im Ausland',
+        'Kundenauftragsposition',
+        'Erlösart',
+        ]

Added: gocept.collmex/trunk/src/gocept/collmex/interfaces.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/src/gocept/collmex/interfaces.py	Mon Oct 13 20:44:36
2008
(at)(at) -0,0 +1,18 (at)(at)
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+
+import zope.interface
+
+
+class ICollmex(zope.interface.Interface):
+    """Python binding for the Collmex API."""
+
+    def create_invoice(items):
+        """Creates an invoice consisting of the given IInvoiceItems."""
+
+
+class IInvoiceItem(zope.interface.Interface):
+    """An invoice item from Collmex.
+
+    Must be able to convert itself into a list.
+    """

Added: gocept.collmex/trunk/src/gocept/collmex/testing.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/src/gocept/collmex/testing.py	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,53 (at)(at)
+# vim:fileencoding=utf-8 -*- coding: utf-8 -*-
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+
+import zope.testbrowser.browser
+
+
+def cleanup_collmex():
+    # Prepare a clean environment in our Collmex testing.
+    b = zope.testbrowser.browser.Browser()
+    b.open('http://www.collmex.de')
+
+    # Login
+    b.getControl('Kunden Nr').value = '42779'
+    b.getControl('anmelden...').click()
+
+    b.getControl('Benutzer').value = '1141688'
+    b.getControl('Kennwort').value = '1416678'
+    b.getControl('Anmelden').click()
+
+    # Firma loeschen
+    b.getLink('Verwaltung').click()
+    b.getLink(u'Löschen').click()
+    b.getControl(u'Zu löschende Daten').displayValue = [
+        'Alle Belege und Stammdaten']
+    b.getControl(u'Ja, wirklich löschen').selected = True
+    b.getControl(u'Daten löschen').click()
+
+    assert 'Daten erfolgreich gel' in b.contents
+
+    # Beispielkunden anlegen
+    b.getLink('Warenwirtschaft').click()
+    add_link = b.getLink(u'Anzeigen und ändern', index=2)
+    assert add_link.url.endswith('cu')
+    add_link.click() # XXX Magic number
+    b.getLink('Anlegen').click()
+    b.getControl('Kunde Nr', index=0).value = '10000'
+    b.getControl('Kunde anlegen').click()
+    b.getControl('Firma').value = 'Testkunden'
+    b.getControl('Speichern').click()
+
+    # Beispielprodukt anlegen
+    b.getLink('Warenwirtschaft').click()
+    add_link = b.getLink(u'Anlegen', index=4)
+    assert add_link.url.endswith('prcr')
+    add_link.click() # XXX Magic number
+    b.getControl('Produkt', index=1).value = 'TRAFFIC'
+    b.getControl('Produkt anlegen').click()
+    b.getControl('Bezeichnung').value = 'Testprodukt'
+    b.getControl('Speichern').click()
+    b.getLink('Verkauf', index=1).click()
+    b.getControl(name='preis_1_preis').value = '5,00'
+    b.getControl('Speichern').click()

Added: gocept.collmex/trunk/src/gocept/collmex/tests.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/src/gocept/collmex/tests.py	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,12 (at)(at)
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+
+import unittest
+import zope.testing.doctest
+
+
+def test_suite():
+    suite = zope.testing.doctest.DocFileSuite(
+        'README.txt',
+        )
+    return suite

Added: gocept.collmex/trunk/src/gocept/collmex/utils.py
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/src/gocept/collmex/utils.py	Mon Oct 13 20:44:36 2008
(at)(at) -0,0 +1,34 (at)(at)
+# copied from http://code.activestate.com/recipes/146306/
+
+import httplib, mimetypes
+
+
+def encode_multipart_formdata(fields, files):
+    """
+    fields is a sequence of (name, value) elements for regular form fields.
+    files is a sequence of (name, filename, value) elements for data to be
uploaded as files
+    Return (content_type, body) ready for httplib.HTTP instance
+    """
+    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
+    CRLF = '\r\n'
+    L = []
+    for (key, value) in fields:
+        L.append('--' + BOUNDARY)
+        L.append('Content-Disposition: form-data; name="%s"' % key)
+        L.append('')
+        L.append(value)
+    for (key, filename, value) in files:
+        L.append('--' + BOUNDARY)
+        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
(key, filename))
+        L.append('Content-Type: %s' % get_content_type(filename))
+        L.append('')
+        L.append(value)
+    L.append('--' + BOUNDARY + '--')
+    L.append('')
+    body = CRLF.join(L)
+    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
+    return content_type, body
+
+
+def get_content_type(filename):
+        return mimetypes.guess_type(filename)[0] or 'application/octet-stream'

SVN: r6802 - in gocept.collmex/trunk: . src
Wolfgang Schnerring <ws(at)gocept.com>
2008-10-13 20:46:04 [ FULL ]
Author: wosc
Date: Mon Oct 13 20:46:03 2008
New Revision: 6802

Log:
svn:ignore


Modified:
   gocept.collmex/trunk/   (props changed)
   gocept.collmex/trunk/src/   (props changed)

SVN: r6803 - gocept.collmex/trunk
Wolfgang Schnerring <ws(at)gocept.com>
2008-10-13 20:46:45 [ FULL ]
Author: wosc
Date: Mon Oct 13 20:46:44 2008
New Revision: 6803

Log:
example local.cfg for collmex login data


Added:
   gocept.collmex/trunk/local.cfg-example

Added: gocept.collmex/trunk/local.cfg-example
==============================================================================
--- (empty file)
+++ gocept.collmex/trunk/local.cfg-example	Mon Oct 13 20:46:44 2008
(at)(at) -0,0 +1,5 (at)(at)
+[test-environment]
+collmex_customer = 4711
+collmex_company = 1
+collmex_username = user
+collmex_password = pass

SVN: r6805 - gocept.collmex/trunk
Wolfgang Schnerring <ws(at)gocept.com>
2008-10-14 11:45:07 [ FULL ]
Author: wosc
Date: Tue Oct 14 11:45:06 2008
New Revision: 6805

Log:
preparing relase


Modified:
   gocept.collmex/trunk/   (props changed)
   gocept.collmex/trunk/CHANGES.txt

Modified: gocept.collmex/trunk/CHANGES.txt
==============================================================================
--- gocept.collmex/trunk/CHANGES.txt	(original)
+++ gocept.collmex/trunk/CHANGES.txt	Tue Oct 14 11:45:06 2008
(at)(at) -1,3 +1,4 (at)(at)
 0.1 (unreleased)
 ----------------
 
+- first release. Supports getting and storing invoices.

SVN: r6809 - gocept.collmex/trunk
Wolfgang Schnerring <ws(at)gocept.com>
2008-10-14 12:03:00 [ FULL ]
Author: wosc
Date: Tue Oct 14 12:02:59 2008
New Revision: 6809

Log:
version bump


Modified:
   gocept.collmex/trunk/CHANGES.txt
   gocept.collmex/trunk/setup.py

Modified: gocept.collmex/trunk/CHANGES.txt
==============================================================================
--- gocept.collmex/trunk/CHANGES.txt	(original)
+++ gocept.collmex/trunk/CHANGES.txt	Tue Oct 14 12:02:59 2008
(at)(at) -1,4 +1,8 (at)(at)
-0.1 (unreleased)
+0.2 (unreleased)
+----------------
+
+
+0.1 (2008-10-14)
 ----------------
 
 - first release. Supports getting and storing invoices.

Modified: gocept.collmex/trunk/setup.py
==============================================================================
--- gocept.collmex/trunk/setup.py	(original)
+++ gocept.collmex/trunk/setup.py	Tue Oct 14 12:02:59 2008
(at)(at) -7,7 +7,7 (at)(at)
 
 setup(
     name='gocept.collmex',
-    version='0.1dev',
+    version='0.2dev',
     author='gocept',
     author_email='mail(at)gocept.com',
     description='A Python API for Collmex import/export',

SVN: r6810 - in gocept.country/trunk: . src/gocept/country
Sebastian Wehrmann <sw(at)gocept.com>
2008-10-14 15:27:33 [ FULL ]
Author: sweh
Date: Tue Oct 14 15:27:31 2008
New Revision: 6810

Log:
- added not-equal compare method for db objects



Modified:
   gocept.country/trunk/CHANGES.txt
   gocept.country/trunk/src/gocept/country/README.txt
   gocept.country/trunk/src/gocept/country/db.py

Modified: gocept.country/trunk/CHANGES.txt
==============================================================================
--- gocept.country/trunk/CHANGES.txt	(original)
+++ gocept.country/trunk/CHANGES.txt	Tue Oct 14 15:27:31 2008
(at)(at) -6,6 +6,11 (at)(at)
 
 - 
 
+0.6.3 (2008-10-14)
+------------------
+
+- Bugfix: added not-equal compare method for db objects
+
 0.6.2 (2008-10-13)
 ------------------
 

Modified: gocept.country/trunk/src/gocept/country/README.txt
==============================================================================
--- gocept.country/trunk/src/gocept/country/README.txt	(original)
+++ gocept.country/trunk/src/gocept/country/README.txt	Tue Oct 14 15:27:31 2008
(at)(at) -340,6 +340,13 (at)(at)
 
   >>> afghanistan == afghanistan2
   True
+  >>> afghanistan != afghanistan2
+  False
+  >>> afghanistan != germany
+  True
+  >>> afghanistan == germany
+  False
+
 
 Comparing with an instance of another class always returns False:
 

Modified: gocept.country/trunk/src/gocept/country/db.py
==============================================================================
--- gocept.country/trunk/src/gocept/country/db.py	(original)
+++ gocept.country/trunk/src/gocept/country/db.py	Tue Oct 14 15:27:31 2008
(at)(at) -29,6 +29,13 (at)(at)
             return False
         return self.token == other.token
 
+    def __ne__(self, other):
+        if not other:
+            return True
+        if other.__class__ != self.__class__:
+            return True
+        return self.token != other.token
+
     def __reduce__(self):
         return (self.__class__, (self.token, ))

SVN: r6813 - in gocept.collmex/trunk: . src/gocept/collmex
Christian Theune <ct(at)gocept.com>
2008-10-14 23:58:13 [ FULL ]
Author: ctheune
Date: Tue Oct 14 23:58:12 2008
New Revision: 6813

Log:
Trying to make a bit more readable.



Modified:
   gocept.collmex/trunk/CHANGES.txt
   gocept.collmex/trunk/README.txt
   gocept.collmex/trunk/setup.py
   gocept.collmex/trunk/src/gocept/collmex/README.txt

Modified: gocept.collmex/trunk/CHANGES.txt
==============================================================================
--- gocept.collmex/trunk/CHANGES.txt	(original)
+++ gocept.collmex/trunk/CHANGES.txt	Tue Oct 14 23:58:12 2008
(at)(at) -1,3 +1,6 (at)(at)
+Changes
+=======
+
 0.2 (unreleased)
 ----------------
 

Modified: gocept.collmex/trunk/README.txt
==============================================================================
--- gocept.collmex/trunk/README.txt	(original)
+++ gocept.collmex/trunk/README.txt	Tue Oct 14 23:58:12 2008
(at)(at) -1,5 +1,11 (at)(at)
-==============
-gocept.collmex
-==============
+.. contents::
 
-A Python binding for the import/export API of Collmex <http://www.collmex.de>.
+Introduction
+============
+
+Collmex is an online ERP system for (small) companies with a focus on simple
+accounting. <http://www.collmex.de>
+
+This package aims to provide pythonic bindings to programm against Collmex'
+API. It includes transaction management for integration with the ZODB or other
+databases that can integrate with the `transaction` package.

Modified: gocept.collmex/trunk/setup.py
==============================================================================
--- gocept.collmex/trunk/setup.py	(original)
+++ gocept.collmex/trunk/setup.py	Tue Oct 14 23:58:12 2008
(at)(at) -10,7 +10,7 (at)(at)
     version='0.2dev',
     author='gocept',
     author_email='mail(at)gocept.com',
-    description='A Python API for Collmex import/export',
+    description='Python-bindings for the Collmex import/export API',
     long_description = (
         open('README.txt').read() +
         '\n\n' +

Modified: gocept.collmex/trunk/src/gocept/collmex/README.txt
==============================================================================
--- gocept.collmex/trunk/src/gocept/collmex/README.txt	(original)
+++ gocept.collmex/trunk/src/gocept/collmex/README.txt	Tue Oct 14 23:58:12 2008
(at)(at) -1,4 +1,3 (at)(at)
-===========
 Collmex API
 ===========
 
(at)(at) -7,6 +6,7 (at)(at)
 API documentation is available at <http://www.collmex.de/cgi-bin/cgi.exe?1005,1,help,api>.
 
 First we need to clean up the Collmex environment:
+
 >>> import gocept.collmex.testing
 >>> gocept.collmex.testing.cleanup_collmex()
 
(at)(at) -21,9 +21,8 (at)(at)
 Traceback (most recent call last):
 APIError: ('204008', 'Fehler in Zeile 1: Benutzer oder Kennwort nicht
korrekt')
 
-
 Invoices
-========
+--------
 
 Invoices can be looked up again, however, the invoice was only registered for
 addition and the transaction needs to be committed first:

SVN: r6814 - gocept.collmex/trunk
Christian Theune <ct(at)gocept.com>
2008-10-15 00:01:46 [ FULL ]
Author: ctheune
Date: Wed Oct 15 00:01:45 2008
New Revision: 6814

Log:
Sprachwarnung.



Modified:
   gocept.collmex/trunk/README.txt

Modified: gocept.collmex/trunk/README.txt
==============================================================================
--- gocept.collmex/trunk/README.txt	(original)
+++ gocept.collmex/trunk/README.txt	Wed Oct 15 00:01:45 2008
(at)(at) -4,8 +4,9 (at)(at)
 ============
 
 Collmex is an online ERP system for (small) companies with a focus on simple
-accounting. <http://www.collmex.de>
+accounting. <http://www.collmex.de> (Note: Collmex
is Germany-based but seems
+to support English. You're bound to stumble over German strings, though.)
 
-This package aims to provide pythonic bindings to programm against Collmex'
+This package aims to provide pythonic bindings to program against Collmex'
 API. It includes transaction management for integration with the ZODB or other
 databases that can integrate with the `transaction` package.

SVN: r6815 - in gocept.reference/trunk: . src/gocept/reference
Thomas Lotze <tl(at)gocept.com>
2008-10-15 08:47:57 [ FULL ]
Author: thomas
Date: Wed Oct 15 08:47:56 2008
New Revision: 6815

Log:
language, ReST


Modified:
   gocept.reference/trunk/README.txt
   gocept.reference/trunk/src/gocept/reference/reference.txt

Modified: gocept.reference/trunk/README.txt
==============================================================================
--- gocept.reference/trunk/README.txt	(original)
+++ gocept.reference/trunk/README.txt	Wed Oct 15 08:47:56 2008
(at)(at) -1,3 +1,6 (at)(at)
+============
+Introduction
+============
 
 This package provides a reference implementation.
 
(at)(at) -11,50 +14,48 (at)(at)
 
 .. contents::
 
-============
-Introduction
-============
 
 Motivation
 ==========
 
-When developing an application we often find the need to reference objects
that
-are managed within the application itself. Those objects are typically `master
-data`-like and are managed centrally within the application.
+When developing an application we often find the need to reference objects
+that are stored as application data. Examples of such objects include
+centrally managed 'master data'.
 
 The reference to those objects is typically intrinsic to the application we
-develop so they should behave like normal Python object references that are
+develop so they should behave like normal Python object references while being
 under the control of our application.
 
 Within the world of Zope and ZODB there are different ways to achieve this.
The
 various approaches have different semantics and side effects. Our goal is to
-unify the way of intrinsically referencing objects and to provide an ability
to
+unify the way of intrinsically referencing objects and to provide the ability
to
 switch between different semantics as needed without rewriting application
code
 and without the need to migrate persistent data structures (at least from the
 application's point of view).
 
+
 Model comparison
 ================
 
 Our goal was to determine the advantages and disadvantages of the different
-approaches. We included three general approaches from the world of
-Python/Zope/ZODB and also the standard relational approach to normalisation
+existing approaches. We included three general approaches from the world of
+Python/Zope/ZODB as well as the standard relational approach to normalisation
 tables.
 
 We used four criteria to describe each solution:
 
 Reference data
-  What data is stored to describe the reference.
+  What data is stored to describe the reference?
 
-Reference semantic
-  What meaning does the reference have? How can the meaning change?
+Reference semantics
+  What meaning does the reference have? How can its meaning change?
 
 Integrity
-  What might happen to my application if data that is involved in the
-  reference might change or become deleted?
+  What might happen to the application if data that is involved in the
+  reference changes or is deleted?
 
 Set/Lookup
-  What do I (as an application developer) have to do to set a reference or
+  What does the application developer have to do to set a reference or
   look up a referenced object?
 
 
(at)(at) -63,19 +64,20 (at)(at)
 ======================    =========================================    
===========================================  
========================================   
====================================================
 Reference data            OID                                           OID   
                                       application-specific key                
   application-specific (primary key + table name)
 
-Reference semantic        Refers to a specific                          Refers
to a spec  ific                        Refers to an object which               
   Refers to an object (row) that is associated
-                          Python object                                 Python
object                                 is associated with the saved key        
   with the primary key at the moment of the lookup.
-                                                                              
                                       at the moment of lookup.
+Reference semantics       Refers to a specific                          Refers
to a specific                          Refers to an object which               
   Refers to an object (row) that is associated
+                          Python object                                 Python
object                                 is associated with the saved key        
   with the primary key at the time of the lookup.
+                                                                              
                                       at the time of the lookup.
 
 Integrity                 The reference stays valid, however,           The
reference might have become stale         The reference might have become      
      Dependening on the use of `foreign keys`
                           the target object might have lost its         and
leave the referencing object in an        stale.                               
      and the databases implementation of constraints.
                           meaning for the application.                 
invalid state.                                                                 
          Can usually be forced to stay valid.
 
-Set/Lookup                Normal Python attribute access.               Use
WeakRef-wrapper to store and              Depends on the implementation.       
      Explicitly store the primary key.
+Set/Lookup                Normal Python attribute access.               Use
WeakRef wrapper to store and              Depends on the implementation.       
      Explicitly store the primary key.
                                                                        
__call__ to lookup. Might use properties      Might use properties for
convenience.       Use JOIN to look up.
                                                                         for
convenience.
 ======================    =========================================    
===========================================  
========================================   
====================================================
 
+
 Observations
 ============
 
(at)(at) -93,21 +95,21 (at)(at)
   a foreign key. This is orthogonal to the data stored.
 
 - Relational: As an application-level key is used for identifying the target
-  of a reference the application can choose to delete a row and re-add a row
+  of a reference, the application can choose to delete a row and re-add a row
   with the same primary key later. If the integrity is enforced this requires
   support on the database level to temporarily ignore broken foreign keys.
 
 - Normal Python references embed themselves naturally in the application.
-  Properties allow hiding implementation on how references are looked
-  up/stored.
+  Properties allow hiding the implementation of looking up and storing
+  references.
 
 
-Conclusions / Requirements for the reference implementation
+Conclusions & Requirements for the reference implementation
 ===========================================================
 [...]

SVN: r6820 - in gocept.reference/trunk: . src/gocept/reference/generations
Michael Howitz <mh(at)gocept.com>
2008-10-16 10:07:51 [ FULL ]
Author: mac
Date: Thu Oct 16 10:07:49 2008
New Revision: 6820

Log:
Fixed: When upgrading gocept.reference to version 0.5.1, a duplication error
was raised.




Modified:
   gocept.reference/trunk/CHANGES.txt
   gocept.reference/trunk/src/gocept/reference/generations/install.py

Modified: gocept.reference/trunk/CHANGES.txt
==============================================================================
--- gocept.reference/trunk/CHANGES.txt	(original)
+++ gocept.reference/trunk/CHANGES.txt	Thu Oct 16 10:07:49 2008
(at)(at) -2,10 +2,11 (at)(at)
 Changes
 =======
 
-0.6 (unreleased)
-================
+0.5.2 (2008-10-16)
+==================
 [...]

SVN: r6841 - in gocept.ooo2html/trunk: . src/gocept/ooo2html src/gocept/ooo2html/testdata
Christian Zagrodnick <cz(at)gocept.com>
2008-10-20 12:37:40 [ FULL ]
Author: zagy
Date: Mon Oct 20 12:37:39 2008
New Revision: 6841

Log:
- Fixed circle-style.



Added:
   gocept.ooo2html/trunk/src/gocept/ooo2html/testdata/657901.odt   (contents,
props changed)
Modified:
   gocept.ooo2html/trunk/CHANGES.txt
   gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
   gocept.ooo2html/trunk/src/gocept/ooo2html/style.py

Modified: gocept.ooo2html/trunk/CHANGES.txt
==============================================================================
--- gocept.ooo2html/trunk/CHANGES.txt	(original)
+++ gocept.ooo2html/trunk/CHANGES.txt	Mon Oct 20 12:37:39 2008
(at)(at) -2,9 +2,11 (at)(at)
 CHANGES
 =======
 
-0.6 (unreleased)
+0.6 (2008-10-20)
 ----------------
 
+- Fixed circle-style.
+
 0.5 (2008-10-13)
 ----------------
 

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	Mon Oct 20 12:37:39
2008
(at)(at) -930,3 +930,23 (at)(at)
     time <br/></span>**) New element of IASS 2009<br/>***)
Please don't
     forger your USB stick &#8211; it was some 4&#160;GB data in
2008!</p>
 ...
+
+
+The circle style wasn't always recognised:
+
+>>> filename = os.path.join(
+...     os.path.dirname(__file__), 'testdata', '657901.odt')
+>>> ooo = file(filename, 'rb+')
+>>> converter = gocept.ooo2html.convert.Converter()
+>>> result = converter.to_html(ooo)
+>>> print result.css
+.Meta,
+...
+ol.WW8Num5 {
+    list-style-type: disc;
+}
+<BLANKLINE>
+ol.WW8Num5 ol {
+    list-style-type: circle;
+}
+...

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/style.py
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/style.py	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/style.py	Mon Oct 20 12:37:39 2008
(at)(at) -160,6 +160,7 (at)(at)
         u'\u2013': 'disc',
         u'\u2022': 'disc',
         u'\u25cb': 'circle',
+        u'o': 'circle',
     }
 
     def get_style_type(self):

Added: gocept.ooo2html/trunk/src/gocept/ooo2html/testdata/657901.odt
==============================================================================
Binary file. No diff available.

SVN: r6883 - in gocept.efs/trunk: . src src/gocept src/gocept/efs
Sebastian Wehrmann <sw(at)gocept.com>
2008-10-23 11:00:02 [ FULL ]
Author: sweh
Date: Thu Oct 23 11:00:00 2008
New Revision: 6883

Log:
initial release



Added:
   gocept.efs/trunk/CHANGES.txt   (contents, props changed)
   gocept.efs/trunk/README.txt   (contents, props changed)
   gocept.efs/trunk/bootstrap.py   (contents, props changed)
   gocept.efs/trunk/setup.py   (contents, props changed)
   gocept.efs/trunk/src/
   gocept.efs/trunk/src/gocept/
   gocept.efs/trunk/src/gocept/__init__.py   (contents, props changed)
   gocept.efs/trunk/src/gocept/efs/
   gocept.efs/trunk/src/gocept/efs/__init__.py   (contents, props changed)

Added: gocept.efs/trunk/CHANGES.txt
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/CHANGES.txt	Thu Oct 23 11:00:00 2008
(at)(at) -0,0 +1,8 (at)(at)
+Changes
+=======
+
+
+0.1 (unreleased)
+----------------
+
+- initial release

Added: gocept.efs/trunk/README.txt
==============================================================================

Added: gocept.efs/trunk/bootstrap.py
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/bootstrap.py	Thu Oct 23 11:00:00 2008
(at)(at) -0,0 +1,55 (at)(at)
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+try:
+    import pkg_resources
+except ImportError:
+    ez = {}
+    exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                         ).read() in ez
+    ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+    import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)

Added: gocept.efs/trunk/setup.py
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/setup.py	Thu Oct 23 11:00:00 2008
(at)(at) -0,0 +1,27 (at)(at)
+from setuptools import setup, find_packages
+import sys, os
+
+version = '0.1'
+
+setup(name='gocept.efs',
+      version=version,
+      description="API for efulfillment service.",
+      long_description="""\
+""",
+      classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+      keywords='',
+      author='Daniel Havlik, Sebastian Wehrmann',
+      author_email='dh(at)gocept.com',
+      url='',
+      license='',
+      packages=find_packages('src'),
+      include_package_data=True,
+    package_dir={'':'src'},
+      zip_safe=False,
+      install_requires=[
+          # -*- Extra requirements: -*-
+      ],
+      entry_points="""
+      # -*- Entry points: -*-
+      """,
+      )

Added: gocept.efs/trunk/src/gocept/__init__.py
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/src/gocept/__init__.py	Thu Oct 23 11:00:00 2008
(at)(at) -0,0 +1,10 (at)(at)
+# Copyright (c) 2007 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+
+#namespace package boilerplate
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError, e:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)

Added: gocept.efs/trunk/src/gocept/efs/__init__.py
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/src/gocept/efs/__init__.py	Thu Oct 23 11:00:00 2008
(at)(at) -0,0 +1 (at)(at)
+#

SVN: r6886 - in gocept.efs/trunk: . src/gocept/efs
Sebastian Wehrmann <sw(at)gocept.com>
2008-10-23 14:24:42 [ FULL ]
Author: sweh
Date: Thu Oct 23 14:24:35 2008
New Revision: 6886

Log:
first release
save new orders in a filestore as raw xml



Added:
   gocept.efs/trunk/src/gocept/efs/README.txt   (contents, props changed)
   gocept.efs/trunk/src/gocept/efs/efs.py   (contents, props changed)
   gocept.efs/trunk/src/gocept/efs/interfaces.py   (contents, props changed)
   gocept.efs/trunk/src/gocept/efs/tests.py   (contents, props changed)
Modified:
   gocept.efs/trunk/setup.py

Modified: gocept.efs/trunk/setup.py
==============================================================================
--- gocept.efs/trunk/setup.py	(original)
+++ gocept.efs/trunk/setup.py	Thu Oct 23 14:24:35 2008
(at)(at) -16,10 +16,14 (at)(at)
       license='',
       packages=find_packages('src'),
       include_package_data=True,
-    package_dir={'':'src'},
+      package_dir={'':'src'},
       zip_safe=False,
       install_requires=[
-          # -*- Extra requirements: -*-
+          'zope.interface',
+          'zope.component',
+          'elementtree',
+          'lxml',
+          'gocept.filestore',
       ],
       entry_points="""
       # -*- Entry points: -*-

Added: gocept.efs/trunk/src/gocept/efs/README.txt
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/src/gocept/efs/README.txt	Thu Oct 23 14:24:35 2008
(at)(at) -0,0 +1,165 (at)(at)
+====================
+eFulfillment Service
+====================
+
+This API allows you to send orders to
+`efulfillment service <http://efulfillmentservice.com/>`_
provider.
+
+Initialization
+--------------
+
+Create a DataProvider and register it as an adapter:
+
+>>> import zope.interface
+>>> import zope.component
+>>> import gocept.efs
+>>> import gocept.efs.interfaces
+>>> import tempfile
+>>> storage_path = tempfile.mkdtemp()
+
+>>> class EfsDataProvider(object):
+...     zope.component.adapts(gocept.efs.interfaces.IEfs)
+...     zope.interface.implements(gocept.efs.interfaces.IEfsDataProvider)
+...
+...     merchant_id = '20'
+...     merchant_name = 'Sesame Street Products'
+...     storage_path = storage_path
+...
+...     def __init__(self, context):
+...         self.context = context
+...
+>>> gsm = zope.component.getGlobalSiteManager()
+>>> gsm.registerAdapter(EfsDataProvider)
+
+Setup the efs API:
+
+>>> import gocept.efs.efs
+>>> efs = gocept.efs.efs.Efs()
+
+To submit an request, we need a shipping- and billingaddress, a shipping
method
+and an order, which contains purchased items:
+
+>>> shipping_address = {'Name': 'John Smith',
+...                     'Company': 'SmithCo',
+...                     'Address1': '123 Test Street',
+...                     'Address2': 'Suite 12',
+...                     'City': 'Highland Park',
+...                     'State': 'NJ',
+...                     'Country': 'US',
+...                     'Zip': '08904',
+...                     'Phone': '555-555-5555',
+...                     'Email': 'test(at)example.com'}
+>>> billing_address = {}
+>>> shipping_method = 'DHLR'
+>>> order = [{'ProductId': '123a', 'Quantity': '1'},
+...          {'ProductId': '123b', 'Quantity': '4'}]
+
+Now, we can call the efs API to submit the request to the efulfillment
service:
+
+>>> efs.create_order(shipping_address, billing_address,
shipping_method,
+...                  '77186', order)
+True
+
+>>> import gocept.filestore
+>>> fs = gocept.filestore.FileStore(storage_path)
+>>> fs.list('tmp')
+[]
+>>> files = fs.list('new')
+>>> len(files)
+1
+>>> file_path = files[0]
+>>> file_path
+'.../new/77186.xml'
+
+The file contains XML formatted data of the submitted order:
+
+>>> xml_file = open(file_path, 'r')
+>>> print xml_file.readline()
+<?xml version="1.0" encoding="utf-8" ?>
+<BLANKLINE>
+>>> print xml_file.readline()
+<!DOCTYPE OrderList SYSTEM "https://fcp.efulfillmentservice.com/xml/OrderList.dtd">
+<BLANKLINE>
+
+>>> import lxml.usedoctest
+>>> print xml_file.read()
+<OrderList MerchantId="20" MerchantName="Sesame Street Products">
+  <Order id="77186">
+    <AddressInfo type="ship">
+      <City>Highland Park</City>
+      <Name>John Smith</Name>
+      <Zip>08904</Zip>
+      <Address1>123 Test Street</Address1>
+      <Company>SmithCo</Company>
+      <Email>test(at)example.com</Email>
+      <Phone>555-555-5555</Phone>
+      <State>NJ</State>
+      <Country>US</Country>
+      <Address2>Suite 12</Address2>
+    </AddressInfo>
+    <ShippingMethod>DHLR</ShippingMethod>
+    <Item num="0">
+      <Quantity>1</Quantity>
+      <ProductId>123a</ProductId>
+    </Item>
+    <Item num="1">
+      <Quantity>4</Quantity>
+      <ProductId>123b</ProductId>
+    </Item>
+  </Order>
+</OrderList>
+
+Now with billing address:
+
+
+>>> billing_address = shipping_address.copy()
+>>> billing_address['Phone'] = '666-666-6666'
+>>> efs.create_order(shipping_address, billing_address,
shipping_method,
+...                  '77187', order)
+True
+>>> files = fs.list('new')
+>>> len(files)
+2
+>>> print open(files[1], 'r').read()
+<OrderList MerchantId="20" MerchantName="Sesame Street Products">
+  <Order id="77187">
+    <AddressInfo type="ship">
+      <City>Highland Park</City>
+      <Name>John Smith</Name>
+      <Zip>08904</Zip>
+      <Address1>123 Test Street</Address1>
+      <Company>SmithCo</Company>
+      <Email>test(at)example.com</Email>
+      <Phone>555-555-5555</Phone>
+      <State>NJ</State>
+      <Country>US</Country>
+      <Address2>Suite 12</Address2>
+    </AddressInfo>
+    <AddressInfo type="bill">
+      <City>Highland Park</City>
+      <Name>John Smith</Name>
+      <Zip>08904</Zip>
+      <Address1>123 Test Street</Address1>
+      <Company>SmithCo</Company>
+      <Phone>666-666-6666</Phone>
+      <State>NJ</State>
+      <Country>US</Country>
+      <Address2>Suite 12</Address2>
+      <Email>test(at)example.com</Email>
+    </AddressInfo>
+    <ShippingMethod>DHLR</ShippingMethod>
+    <Item num="0">
+      <Quantity>1</Quantity>
+      <ProductId>123a</ProductId>
+    </Item>
+    <Item num="1">
+      <Quantity>4</Quantity>
+      <ProductId>123b</ProductId>
+    </Item>
+  </Order>
+</OrderList>
+
+Delete the temporary storage path:
+
+>>> import shutil
+>>> shutil.rmtree(storage_path)

Added: gocept.efs/trunk/src/gocept/efs/efs.py
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/src/gocept/efs/efs.py	Thu Oct 23 14:24:35 2008
(at)(at) -0,0 +1,50 (at)(at)
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+
+import zope.interface
+import gocept.efs.interfaces
+import gocept.filestore
+import elementtree.SimpleXMLWriter
+
+class Efs(object):
+    """API for the efulfillment service."""
+    zope.interface.implements(gocept.efs.interfaces.IEfs)
+
+    def create_order(self, shipping_address, billing_address, shipping_method,
+                     order_id, order):
+        efs_data = gocept.efs.interfaces.IEfsDataProvider(self)
+        fs = gocept.filestore.FileStore(efs_data.storage_path)
+        fs.prepare()
+        filename = '%s.xml' % order_id
+        xml_file = fs.create(filename)
+        xml_file.write('<?xml version="1.0" encoding="utf-8" ?>\n')
+        xml_file.write('<!DOCTYPE OrderList SYSTEM "https://fcp.efulfillmentservice.com/xml/OrderList.dtd">\n')
+
+        writer = elementtree.SimpleXMLWriter.XMLWriter(xml_file, 'utf-8')
+        e_orderlist = writer.start("OrderList",
+                                 MerchantName=efs_data.merchant_name,
+                                 MerchantId=efs_data.merchant_id)
+        e_order = writer.start("Order", {'id': order_id})
+        e_shipping = writer.start("AddressInfo", {'type': 'ship'})
+        for key, value in shipping_address.items():
+            writer.element(key, value)
+        writer.close(e_shipping)
+        if billing_address:
+            e_billing = writer.start("AddressInfo", {'type': 'bill'})
+            for key, value in billing_address.items():
+                writer.element(key, value)
+            writer.close(e_billing)
+        writer.element("ShippingMethod", shipping_method)
+        item_num = 0
+        for order_item in order:
+            item = writer.start("Item", {'num': str(item_num)})
+            item_num += 1
+            for key, value in order_item.items():
+                writer.element(key, value)
+            writer.close(item)
+        writer.close(e_order)
+        writer.close(e_orderlist)
+        xml_file.close()
+        fs.move(filename, 'tmp', 'new')
+        return True

Added: gocept.efs/trunk/src/gocept/efs/interfaces.py
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/src/gocept/efs/interfaces.py	Thu Oct 23 14:24:35 2008
(at)(at) -0,0 +1,21 (at)(at)
+# Copyright (c) 2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+
+import zope.interface
+
+
+class IEfs(zope.interface.Interface):
+    """API for the efulfillment service."""
+
+    def create_order(shipping_address, billing_address, shipping_method,
+                     order_id, order):
+        """Submit the data to the XML-RPC server.""" 
+
+
+class IEfsDataProvider(zope.interface.Interface):
+    """The data provider for the efs."""
+
+    merchant_id = zope.interface.Attribute('Merchant ID')
+    merchant_name = zope.interface.Attribute('Merchant name')
+    storage_path = zope.interface.Attribute('Storage path')

Added: gocept.efs/trunk/src/gocept/efs/tests.py
==============================================================================
--- (empty file)
+++ gocept.efs/trunk/src/gocept/efs/tests.py	Thu Oct 23 14:24:35 2008
(at)(at) -0,0 +1,14 (at)(at)
+# Copyright (c) 2007-2008 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+
+import unittest
+
+from zope.testing import doctest
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocFileSuite("README.txt",
+                                       optionflags=doctest.ELLIPSIS))
+    return suite

SVN: r6897 - gocept.efs/trunk/src/gocept/efs
Daniel Havlik <dh(at)gocept.com>
2008-10-24 10:29:22 [ FULL ]
Author: nilo
Date: Fri Oct 24 10:29:20 2008
New Revision: 6897

Log:
efs now uses a data adapter for getting its data



Modified:
   gocept.efs/trunk/src/gocept/efs/README.txt
   gocept.efs/trunk/src/gocept/efs/efs.py
   gocept.efs/trunk/src/gocept/efs/interfaces.py

Modified: gocept.efs/trunk/src/gocept/efs/README.txt
==============================================================================
--- gocept.efs/trunk/src/gocept/efs/README.txt	(original)
+++ gocept.efs/trunk/src/gocept/efs/README.txt	Fri Oct 24 10:29:20 2008
(at)(at) -8,33 +8,23 (at)(at)
 Initialization
 --------------
 
-Create a DataProvider and register it as an adapter:
-
 >>> import zope.interface
 >>> import zope.component
+
+Create a DataProvider and register it as an adapter:
+
 >>> import gocept.efs
 >>> import gocept.efs.interfaces
 >>> import tempfile
 >>> storage_path = tempfile.mkdtemp()
 
->>> class EfsDataProvider(object):
-...     zope.component.adapts(gocept.efs.interfaces.IEfs)
-...     zope.interface.implements(gocept.efs.interfaces.IEfsDataProvider)
-...
-...     merchant_id = '20'
-...     merchant_name = 'Sesame Street Products'
-...     storage_path = storage_path
-...
-...     def __init__(self, context):
-...         self.context = context
-...
->>> gsm = zope.component.getGlobalSiteManager()
->>> gsm.registerAdapter(EfsDataProvider)
-
 Setup the efs API:
 
+>>> merchant_id = '20'
+>>> merchant_name = 'Sesame Street Products'
+>>> storage_path = storage_path
 >>> import gocept.efs.efs
->>> efs = gocept.efs.efs.Efs()
+>>> efs = gocept.efs.efs.Efs(merchant_id, merchant_name,
storage_path)
 
 To submit an request, we need a shipping- and billingaddress, a shipping
method
 and an order, which contains purchased items:
(at)(at) -54,10 +44,38 (at)(at)
 >>> order = [{'ProductId': '123a', 'Quantity': '1'},
 ...          {'ProductId': '123b', 'Quantity': '4'}]
 
+>>> class IMyOrder(zope.interface.Interface):
+...     pass
+
+>>> class MyOrder(object):
+...     zope.interface.implements(IMyOrder)
+
+
+>>> firstorder = MyOrder()
+>>> firstorder.shipping_address = shipping_address
+>>> firstorder.billing_address = {}
+>>> firstorder.order = order
+>>> firstorder.shipping_method = shipping_method
+>>> firstorder.order_id = '77186'
+
+>>> class EfsMyOrder(object):
+...     zope.interface.implements(gocept.efs.interfaces.IEfsData)
+...     zope.component.adapts(IMyOrder)
+...
+...     def __init__(self, context):
+...         self.context = context
+...         self.shipping_address = context.shipping_address
+...         self.billing_address = context.billing_address
+...         self.order = context.order
+...         self.shipping_method = context.shipping_method
+...         self.order_id = context.order_id
+
+>>> gsm = zope.component.getGlobalSiteManager()
+>>> gsm.registerAdapter(EfsMyOrder)
+
 Now, we can call the efs API to submit the request to the efulfillment
service:
 
->>> efs.create_order(shipping_address, billing_address,
shipping_method,
-...                  '77186', order)
+>>> efs.create_order(firstorder)
 True
 
 >>> import gocept.filestore
(at)(at) -111,11 +129,12 (at)(at)
 
 Now with billing address:
 
-
 >>> billing_address = shipping_address.copy()
 >>> billing_address['Phone'] = '666-666-6666'
->>> efs.create_order(shipping_address, billing_address,
shipping_method,
-...                  '77187', order)
+>>> secondorder = firstorder
+>>> secondorder.billing_address = billing_address
+>>> secondorder.order_id = '77187'
+>>> efs.create_order(secondorder)
 True
 >>> files = fs.list('new')
 >>> len(files)

Modified: gocept.efs/trunk/src/gocept/efs/efs.py
==============================================================================
--- gocept.efs/trunk/src/gocept/efs/efs.py	(original)
+++ gocept.efs/trunk/src/gocept/efs/efs.py	Fri Oct 24 10:29:20 2008
(at)(at) -11,33 +11,37 (at)(at)
     """API for the efulfillment service."""
     zope.interface.implements(gocept.efs.interfaces.IEfs)
 
-    def create_order(self, shipping_address, billing_address, shipping_method,
-                     order_id, order):
-        efs_data = gocept.efs.interfaces.IEfsDataProvider(self)
-        fs = gocept.filestore.FileStore(efs_data.storage_path)
+    def __init__(self, merchant_name, merchant_id, storage_path):
+        self.merchant_name = merchant_name
+        self.merchant_id = merchant_id
+        self.storage_path = storage_path
+
+    def create_order(self, obj):
+        efsdata = gocept.efs.interfaces.IEfsData(obj)
+        fs = gocept.filestore.FileStore(self.storage_path)
         fs.prepare()
-        filename = '%s.xml' % order_id
+        filename = '%s.xml' % efsdata.order_id
         xml_file = fs.create(filename)
         xml_file.write('<?xml version="1.0" encoding="utf-8" ?>\n')
         xml_file.write('<!DOCTYPE OrderList SYSTEM "https://fcp.efulfillmentservice.com/xml/OrderList.dtd">\n')
 
         writer = elementtree.SimpleXMLWriter.XMLWriter(xml_file, 'utf-8')
         e_orderlist = writer.start("OrderList",
-                                 MerchantName=efs_data.merchant_name,
-                                 MerchantId=efs_data.merchant_id)
-        e_order = writer.start("Order", {'id': order_id})
+                                 MerchantName=self.merchant_name,
+                                 MerchantId=self.merchant_id)
+        e_order = writer.start("Order", {'id': efsdata.order_id})
         e_shipping = writer.start("AddressInfo", {'type': 'ship'})
-        for key, value in shipping_address.items():
+        for key, value in efsdata.shipping_address.items():
             writer.element(key, value)
         writer.close(e_shipping)
-        if billing_address:
+        if efsdata.billing_address:
             e_billing = writer.start("AddressInfo", {'type': 'bill'})
-            for key, value in billing_address.items():
+            for key, value in efsdata.billing_address.items():
                 writer.element(key, value)
             writer.close(e_billing)
-        writer.element("ShippingMethod", shipping_method)
+        writer.element("ShippingMethod", efsdata.shipping_method)
         item_num = 0
-        for order_item in order:
+        for order_item in efsdata.order:
             item = writer.start("Item", {'num': str(item_num)})
             item_num += 1
             for key, value in order_item.items():

Modified: gocept.efs/trunk/src/gocept/efs/interfaces.py
==============================================================================
--- gocept.efs/trunk/src/gocept/efs/interfaces.py	(original)
+++ gocept.efs/trunk/src/gocept/efs/interfaces.py	Fri Oct 24 10:29:20 2008
(at)(at) -4,18 +4,30 (at)(at)
 
 import zope.interface
 
+class IEfsData(zope.interface.Interface):
+    """Interface for EfsData objects which can be implemented 
+    as adapter to convert an object to an efs order"""
+    shipping_address = zope.interface.Attribute('''dict with keys:
+        Name Company Address1 Address2 City State Country Zip Phone Email''')
+    billing_address = zope.interface.Attribute('''dict with keys:
+        Name Company Address1 Address2 City State Country Zip Phone Email''')
+    shipping_method = zope.interface.Attribute(
+            'string defining the shipping method')
+    order_id = zope.interface.Attribute('an order id')
+    order = zope.interface.Attribute(
+            'list of dicts with keys: "ProductId", "Quantity"')
+
 
 class IEfs(zope.interface.Interface):
     """API for the efulfillment service."""
 
-    def create_order(shipping_address, billing_address, shipping_method,
-                     order_id, order):
-        """Submit the data to the XML-RPC server.""" 
-
-
-class IEfsDataProvider(zope.interface.Interface):
-    """The data provider for the efs."""
-
     merchant_id = zope.interface.Attribute('Merchant ID')
     merchant_name = zope.interface.Attribute('Merchant name')
     storage_path = zope.interface.Attribute('Storage path')
+
+    def create_order(order_obj):
+        """Submit the data to the XML-RPC server.
+
+        order_obj:: Object that can be adapted to IEfsData
+        """
+

SVN: r6898 - gocept.efs/trunk/src/gocept/efs
Daniel Havlik <dh(at)gocept.com>
2008-10-24 10:31:23 [ FULL ]
Author: nilo
Date: Fri Oct 24 10:31:22 2008
New Revision: 6898

Log:
wrong order of positional arguments fixed



Modified:
   gocept.efs/trunk/src/gocept/efs/efs.py

Modified: gocept.efs/trunk/src/gocept/efs/efs.py
==============================================================================
--- gocept.efs/trunk/src/gocept/efs/efs.py	(original)
+++ gocept.efs/trunk/src/gocept/efs/efs.py	Fri Oct 24 10:31:22 2008
(at)(at) -11,7 +11,7 (at)(at)
     """API for the efulfillment service."""
     zope.interface.implements(gocept.efs.interfaces.IEfs)
 
-    def __init__(self, merchant_name, merchant_id, storage_path):
+    def __init__(self, merchant_id, merchant_name, storage_path):
         self.merchant_name = merchant_name
         self.merchant_id = merchant_id
         self.storage_path = storage_path

MailBoxer