|
/
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 – it was some 4 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
|
|