"packing slip" objects) without subclassing. (This is particularly useful if |
"packing slip" objects) without subclassing. (This is particularly useful if |
you are extending a CRM or other database that was written by somebody else.) |
you are extending a CRM or other database that was written by somebody else.) |
|
|
|
This version of PyDicia is an alpha proof-of-concept release. It is actually |
|
usable -- I've already used it to print about a dozen international shipping |
|
labels to almost as many countries. However, the API is subject to change, |
|
the reference documentation is sketchy, and the developer's guide lacks detail |
|
about some of the more advanced features. This should improve in future |
|
releases, but I just want to get this milestone out to start with. Reading the |
|
DAZzle XML API specification is a good idea if you want to use this; make sure |
|
you get the 7.0.x version, as that's required. |
|
|
PyDicia uses the ElementTree, simplegeneric, and DecoratorTools packages, and |
PyDicia uses the ElementTree, simplegeneric, and DecoratorTools packages, and |
requires Python 2.4 or higher (due to use of decorators and the ``Decimal`` |
requires Python 2.4 or higher (due to use of decorators and the ``Decimal`` |
type). |
type). Actually printing any labels requires that you have an Endicia |
|
"Premium" or "Mac" account. (Note: I have not used the Mac client, so I don't |
|
know how well it works there. See the section below on `Using PyDicia on |
|
Non-Windows Platforms`_ for more info.) |
|
|
|
Questions, discussion, and bug reports for this software should be directed to |
|
the PEAK mailing list; see http://www.eby-sarna.com/mailman/listinfo/PEAK/ |
|
for details. |
|
|
IMPORTANT |
IMPORTANT |
Please note that PyDicia does not attempt to implement all of the US Postal |
Please note that PyDicia does not attempt to implement all of the US Postal |
been warned! |
been warned! |
|
|
|
|
TODO: |
.. contents:: **Table of Contents** |
|
|
* Cmd-line and queue mode handlers |
|
|
|
* Response parsing and application |
|
|
|
|
|
----------------- |
----------------- |
|
|
The ``add_package()`` method accepts zero or more objects that can manipulate |
The ``add_package()`` method accepts zero or more objects that can manipulate |
PyDicia package objects. It also accepts tuples or lists of such objects, |
PyDicia package objects. It also accepts tuples or lists of such objects, |
nested to arbitrary depth. |
nested to arbitrary depth:: |
|
|
>>> b.add_package([COD, (Stealth, ToName('Ty Sarna'))], FlatRateBox) |
>>> b.add_package([Services.COD, (Stealth, ToName('Ty Sarna'))], FlatRateBox) |
|
|
>>> print b.tostring() |
>>> print b.tostring() |
<DAZzle> |
<DAZzle> |
have been passed to ``add_package()``:: |
have been passed to ``add_package()``:: |
|
|
>>> b.packages |
>>> b.packages |
[(Option('ToName', 'Phillip Eby', None),), |
[Package(ToName('Phillip Eby'),), |
([Option('Services', 'ON', 'COD'), (Option('Stealth', 'TRUE', None), |
Package([Services.COD('ON'), (Stealth('TRUE'), ToName('Ty Sarna'))], |
Option('ToName', 'Ty Sarna', None))], |
PackageType('FLATRATEBOX'))] |
Option('PackageType', 'FLATRATEBOX', None))] |
|
|
Each package object in the list wraps a tuple of the arguments that were |
Each "package" in the list is a tuple of the arguments that were supplied for |
supplied for each invocation of ``add_package()``. This allows the system |
each invocation of ``add_package()``. |
to send status updates (including delivery confirmation numbers, customs IDs, |
|
etc.) back to the application. |
|
|
Treating Your Objects as Packages |
But before we can process status updates, we need to have some application |
--------------------------------- |
objects, as described in the next section. |
|
|
It also accepts any custom objects of your own design, that are registered with |
|
the ``pydicia.add_to_package()`` or ``pydicia.iter_options()`` generic |
Using Your Application Objects as Package Sources |
functions:: |
------------------------------------------------- |
|
|
|
In addition to PyDicia-defined objects and sequences thereof, the |
|
``add_package()`` method also accepts any custom objects of your own design |
|
that have been registered with the ``pydicia.add_to_package()`` or |
|
``pydicia.iter_options()`` generic functions:: |
|
|
>>> class Customer: |
>>> class Customer: |
... def __init__(self, **kw): |
... def __init__(self, **kw): |
</Package> |
</Package> |
</DAZzle> |
</DAZzle> |
|
|
Also note that there is no particular significance to my choice of lists vs. |
Note that there is no particular significance to my choice of lists vs. tuples |
tuples in these examples; they're more to demonstrate that you can use |
in these examples; they're more to demonstrate that you can use arbitrary |
arbitrary structures, as long as they contain objects that are supported by |
structures, as long as they contain objects that are supported by either |
either ``iter_options()`` or ``add_to_package()``. Normally, you will simply |
``iter_options()`` or ``add_to_package()``. Normally, you will simply use |
use collections of either PyDicia-provided symbols, or application objects for |
collections of either PyDicia-provided symbols, or application objects for |
which you've defined an ``iter_options()`` method. |
which you've defined an ``iter_options()`` method. |
|
|
You will also usually want to implement your PyDicia support in a module by |
You will also usually want to implement your PyDicia support in a module by |
Multi-Batch Shipments |
Multi-Batch Shipments |
===================== |
===================== |
|
|
Certain DAZzle options can only be set once per file, such as the choice of |
Certain DAZzle options can only be set once per XML file, such as the choice of |
layout file. If you are shipping multiple packages with different label |
layout file. If you are shipping multiple packages with different label |
layouts (such as domestic vs. international mail), you need to separate these |
layouts (such as domestic vs. international mail), you need to separate these |
packages into different batches. The ``Shipment`` class handles this |
packages into different batches, each of which will be in a separate XML file. |
separation for you automatically. |
The ``Shipment`` class handles this separation for you automatically. |
|
|
When you create a shipment, it initially has no batches:: |
When you create a shipment, it initially has no batches:: |
|
|
|
|
But as you add packages to it, it will create batches as needed:: |
But as you add packages to it, it will create batches as needed:: |
|
|
>>> s.add_package(ToName('Phillip Eby'), Test) |
>>> s.add_package(ToName('Phillip Eby'), DAZzle.Test) |
>>> len(s.batches) |
>>> len(s.batches) |
1 |
1 |
|
|
As long as you're adding packages with the same or compatible options, the |
As long as you're adding packages with the same or compatible options, the |
same batch will be reused:: |
same batch will be reused:: |
|
|
>>> s.add_package(ToName('Ty Sarna'), Test) |
>>> s.add_package(ToName('Ty Sarna'), DAZzle.Test) |
>>> len(s.batches) |
>>> len(s.batches) |
1 |
1 |
>>> print s.batches[0].tostring() |
>>> print s.batches[0].tostring() |
But as soon as you add a package with any incompatible options, a new batch |
But as soon as you add a package with any incompatible options, a new batch |
will be created and used:: |
will be created and used:: |
|
|
>>> s.add_package(ToName('PJE'), ~Test) |
>>> s.add_package(ToName('PJE'), ~DAZzle.Test) |
>>> len(s.batches) |
>>> len(s.batches) |
2 |
2 |
|
|
|
|
And each time you add a package, it's added to the first compatible batch:: |
And each time you add a package, it's added to the first compatible batch:: |
|
|
>>> s.add_package(ToName('Some Body'), ~Test) |
>>> s.add_package(ToName('Some Body'), ~DAZzle.Test) |
>>> len(s.batches) |
>>> len(s.batches) |
2 |
2 |
|
|
</Package> |
</Package> |
</DAZzle> |
</DAZzle> |
|
|
>>> s.add_package(ToName('No Body'), Test) |
>>> s.add_package(ToName('No Body'), DAZzle.Test) |
>>> len(s.batches) |
>>> len(s.batches) |
2 |
2 |
|
|
By the way, as with batches, you can create a shipment with options that will |
By the way, as with batches, you can create a shipment with options that will |
be applied to all packages:: |
be applied to all packages:: |
|
|
>>> s = Shipment(Tomorrow, COD) |
>>> s = Shipment(Tomorrow, Services.COD) |
>>> s.add_package(ToName('Some Body'), Test) |
>>> s.add_package(ToName('Some Body'), DAZzle.Test) |
>>> s.add_package(ToName('No Body'), ~Test) |
>>> s.add_package(ToName('No Body'), ~DAZzle.Test) |
>>> len(s.batches) |
>>> len(s.batches) |
2 |
2 |
>>> print s.batches[0].tostring() |
>>> print s.batches[0].tostring() |
|
|
|
|
|
|
Invoking DAZzle |
Receiving Status Updates |
=============== |
======================== |
|
|
|
When DAZzle completes a batch, it creates an output file containing status |
|
information for each package in the batch. If you'd like to process this |
|
status information for the corresponding application objects you passed in |
|
to ``add_package()``, you can extend the ``report_status()`` generic function |
|
to do this:: |
|
|
|
>>> @report_status.when_type(Customer) |
|
... def customer_status(ob, status): |
|
... print ob |
|
... print status |
|
|
|
>>> b = Batch() |
|
>>> b.add_package(c) |
|
|
|
When the batch receives status information, it will invoke ``report_status()`` |
|
on each package's application items, with a status object for the corresponding |
|
package:: |
|
|
|
>>> b.report_statuses() |
|
<...Customer instance...> |
|
ToAddress : [u'123 Nowhere Dr'] |
|
ToCity : u'Nowhere' |
|
ToState : u'FL' |
|
ToPostalCode : u'12345-6789' |
|
ToAddress1 : u'123 Nowhere Dr' |
|
|
|
Note that you don't normally need to call ``report_statuses()`` directly; it's |
|
usually done for you as part of the process of running a batch or shipment. |
|
(See the section below on `Invoking DAZzle`_.) |
|
|
|
The `status` object passed to your method will be a ``Status`` instance with |
|
attributes similar to those above, containing USPS-normalized address data. |
|
In addition, several other fields are possible:: |
|
|
|
>>> from pydicia import ET |
|
>>> b.etree = ET.fromstring(''' |
|
... <DAZzle><Package ID="1"> |
|
... <ToZip4>1234</ToZip4> |
|
... <Status>Rejected (-3)</Status> |
|
... <PIC>123465874359</PIC> |
|
... <FinalPostage>4.60</FinalPostage> |
|
... <TransactionDateTime>20070704173221</TransactionDateTime> |
|
... <PostmarkDate>20070705</PostmarkDate> |
|
... </Package></DAZzle>''') |
|
|
|
>>> b.report_statuses() |
|
<...Customer instance...> |
|
Status : 'Rejected (-3)' |
|
ErrorCode : -3 |
|
ToAddress : [] |
|
ToZip4 : '1234' |
|
PIC : '123465874359' |
|
FinalPostage : Decimal("4.60") |
|
TransactionDateTime : datetime.datetime(2007, 7, 4, 17, 32, 21) |
|
PostmarkDate : datetime.date(2007, 7, 5) |
|
|
|
The ``Status`` object should support all output fields supported by DAZzle; see |
|
the DAZzle documentation for details. The non-string fields shown above are |
|
the only ones which are postprocessed to specialized Python objects; the rest |
|
are kept as strings or Unicode values. The ``ErrorCode`` field is computed by |
|
extracting the integer portion of any rejection code. It is ``None`` in the |
|
case of a successful live print, and ``0`` in the case of a successful test |
|
print. See the DAZzle XML interface documentation for a description of other |
|
error codes. |
|
|
|
Note that for a more compact presentation, attributes with ``None`` values are |
|
not included in the ``str()`` of a ``Status`` object, which is why the statuses |
|
displayed above show different sets of fields. The attributes, however, always |
|
exist; they simply have ``None`` as their value. |
|
|
XXX |
|
|
|
|
Invoking DAZzle |
|
=============== |
|
|
Application Integration |
In the simplest case, invoking a batch or shipment objects ``.run()`` method |
======================= |
will launch a local copy of DAZzle on a temporary file containing the batch's |
|
XML, wait for DAZzle to exit, then process status updates from the output file |
|
and return DAZzle's return code. (Or a list of return codes, in the case of a |
|
``Shipment``.) |
|
|
|
If you are using this approach, you may wish to include ``~DAZzle.Prompt`` |
|
(which keeps end-user prompts to a minimum) and ``DAZzle.AutoClose`` (so that |
|
DAZzle exits upon completion of the batch) in your batch options. |
|
|
|
If you do not have a local copy of DAZzle, but instead are using a network |
|
queue directory to send jobs remotely, you can instead use the batch object's |
|
``.write(queuedir)`` method to send the batch to the queue. You can also |
|
use this approach to send jobs to a local copy of DAZzle running in the |
|
background. |
|
|
|
If a copy of DAZzle is installed locally, you can get its XML queue directory |
|
from ``DAZzle.XMLDirectory``, and check whether it is monitoring for files |
|
using ``DAZzle.get_preference("MonitorXML")``. (These values will be ``None`` |
|
if DAZzle is not installed.) |
|
|
|
If DAZzle is installed locally, you can launch it with the |
|
``DAZzle.run(args=(), sync=True)`` function. The `args` are a list of command |
|
line arguments to pass, and `sync` is a flag indicating whether to wait for |
|
DAZzle to exit. If `sync` is a false value, ``run()`` returns a |
|
``subprocess.Popen`` instance. Otherwise, it returns the process's exit code |
|
(ala ``subprocess.call``). |
|
|
|
XXX async batch status retrieval |
|
|
|
XXX DAZzle.exe_path, DAZzle.get_preference(), DAZzle.LayoutDirectory |
|
|
|
XXX Launching for multi-batch, remote, queued, and other async processing |
|
|
|
|
|
Using PyDicia on Non-Windows Platforms |
|
====================================== |
|
|
|
When used on a non-Windows platform, PyDicia cannot detect any DAZzle |
|
configuration information, so you must manually set ``DAZzle.exe_path`` to |
|
the client program, if you wish to use any of the ``run()`` methods. |
|
(Likewise, you must manually set ``DAZzle.LayoutDirectory`` if you want layout |
|
paths to be automatically adjusted.) |
|
|
|
On the Mac, the ``exe_path`` should be set to a program that takes a single |
|
XML filename as an argument. The Mac ``endiciatool`` program probably will |
|
not work on its own, without a wrapper shell script of some kind; I'm open to |
|
suggestions as to how to improve this. Note, by the way, that the Mac client |
|
doesn't support all of the options that the Windows client does, so remember |
|
that use of PyDicia is entirely at your own risk, whatever the platform! |
|
|
|
On other platforms, the main usefulness of PyDicia would be in generating XML |
|
for users to download (e.g. from a web application) or submitting and |
|
processing jobs via a Samba-mounted queue directory. You don't need an |
|
``exe_path`` for this, but you will need to generate your own layout and output |
|
file paths using ``Option`` objects, to avoid them being mangled by PyDicia's |
|
platform-specific path munging. |
|
|
Status handling, Address updating, ToReturnCode()... |
XXX explain how to do that, or make it work anyway |
|
|
|
|
Advanced Customization |
Advanced Customization |
====================== |
====================== |
|
|
Using Option elements, add_to_package() |
XXX Using Option elements, add_to_package() |
|
|
|
|
|
|
----------------- |
----------------- |
Basic Package Options |
Basic Package Options |
===================== |
===================== |
|
|
MailClass(text), NoPostage |
XXX MailClass(text), NoPostage |
|
|
DateAdvance(), Today, Tomorrow |
DateAdvance(), Today, Tomorrow |
Value() |
Value() |
Description() |
Description() |
Addresses |
Addresses |
========= |
========= |
|
|
|
:: |
>>> ToName("Phillip J. Eby") |
>>> ToName("Phillip J. Eby") |
Option('ToName', 'Phillip J. Eby', None) |
ToName('Phillip J. Eby') |
|
|
>>> ToTitle("President") |
>>> ToTitle("President") |
Option('ToTitle', 'President', None) |
ToTitle('President') |
|
|
>>> ToCompany("Dirt Simple, Inc.") |
>>> ToCompany("Dirt Simple, Inc.") |
Option('ToCompany', 'Dirt Simple, Inc.', None) |
ToCompany('Dirt Simple, Inc.') |
|
|
|
|
ToAddress(*lines) |
XXX ToAddress(\*lines) |
ToCity(text), ToState(text), ToPostalCode(text), ToZIP4(text), ToCountry(text) |
ToCity(text), ToState(text), ToPostalCode(text), ToZIP4(text), ToCountry(text) |
|
|
ReturnAddress(*lines) |
XXX ReturnAddress(\*lines) |
|
|
ToDeliveryPoint(text) |
ToDeliveryPoint(text) |
EndorsementLine(text) |
EndorsementLine(text) |
ToCarrierRoute(text) |
ToCarrierRoute(text) |
Package Details |
Package Details |
=============== |
=============== |
|
|
PackageType() |
XXX PackageType() |
FlatRateEnvelope |
FlatRateEnvelope |
FlatRateBox |
FlatRateBox |
RectangularParcel |
RectangularParcel |
Postcard |
Postcard |
Flat |
Flat |
Envelope |
Envelope |
|
|
Width(), Length(), Depth() |
Width(), Length(), Depth() |
|
|
NonMachinable |
NonMachinable |
BalloonRate |
BalloonRate |
|
|
|
|
|
|
Service Options |
Service Options |
=============== |
=============== |
|
|
ReplyPostage |
XXX ReplyPostage |
Stealth |
Stealth |
|
|
SignatureWaiver |
SignatureWaiver |
NoWeekendDelivery |
NoWeekendDelivery |
NoHolidayDelivery |
NoHolidayDelivery |
ReturnToSender |
ReturnToSender |
|
|
Insurance.USPS |
Insurance.USPS |
Insurance.Endicia |
Insurance.Endicia |
Insurance.UPIC |
Insurance.UPIC |
Insurance.NONE |
Insurance.NONE |
|
Services.RegisteredMail |
RegisteredMail |
Services.CertifiedMail |
CertifiedMail |
Services.RestrictedDelivery |
RestrictedDelivery |
Services.CertificateOfMailing |
CertificateOfMailing |
Services.ReturnReceipt |
ReturnReceipt |
Services.DeliveryConfirmation |
DeliveryConfirmation |
Services.SignatureConfirmation |
SignatureConfirmation |
Services.COD |
COD |
Services.InsuredMail() |
|
|
|
|
Customs Forms |
Customs Forms |
============= |
============= |
|
|
Customs.Sample |
When processing international shipments, you will usually need to specify a |
Customs.Gift |
customs form, contents type, and items. Additionally, if you want to print |
Customs.Documents |
the customs forms already "signed", you can specify a signer and the |
Customs.Other |
certification option. |
Customs.Merchandise |
|
|
Contents Types |
Customs.GEM |
-------------- |
Customs.CN22 |
|
Customs.CP72 |
The ``ContentsType`` constructor defines the type of contents declared on the |
Customs.NONE |
customs form. There are six predefined constants for the standard contents |
|
types:: |
|
|
|
>>> Customs.Sample |
|
ContentsType('SAMPLE') |
|
|
|
>>> Customs.Gift |
|
ContentsType('GIFT') |
|
|
|
>>> Customs.Documents |
|
ContentsType('DOCUMENTS') |
|
|
|
>>> Customs.Other |
|
ContentsType('OTHER') |
|
|
|
>>> Customs.Merchandise |
|
ContentsType('MERCHANDISE') |
|
|
|
>>> Customs.ReturnedGoods |
|
ContentsType('RETURNEDGOODS') |
|
|
Customs.Item(desc, weight, value, qty=1, origin='United States') |
|
|
|
Customs.Signer(text) |
Customs Form Types |
Customs.Certify |
------------------ |
|
|
|
The ``CustomsFormType`` constructor defines the type of customs form to be |
|
used. There are four predefined constants for the allowed form types:: |
|
|
|
>>> Customs.GEM |
|
CustomsFormType('GEM') |
|
|
|
>>> Customs.CN22 |
|
CustomsFormType('CN22') |
|
|
|
>>> Customs.CP72 |
|
CustomsFormType('CP72') |
|
|
|
>>> Customs.NONE |
|
CustomsFormType('NONE') |
|
|
|
|
|
Customs Items |
|
------------- |
|
|
|
Items to be declared on a customs form are created using ``Customs.Item``. |
|
The minimum required arguments are a description, a unit weight in ounces |
|
(which must be an integer or decimal), and a value in US dollars (also an |
|
integer or decimal):: |
|
|
|
>>> from decimal import Decimal |
|
>>> i = Customs.Item("Paperback book", 12, Decimal('29.95')) |
|
|
|
You may also optionally specify a quantity (which must be an integer) and a |
|
country of origin. The defaults for these are ``1`` and ``"United States"``, |
|
respectively:: |
|
|
|
>>> i |
|
Item('Paperback book', Decimal("12"), Decimal("29.95"), 1, 'United States') |
|
|
|
You always specify a unit weight and value; these are automatically multiplied |
|
by the quantity on the customs form, and for purposes of calculating total |
|
weight/value. |
|
|
|
Note that a package's total weight must be greater than or equal to the sum of |
|
its items' weight, and its value must exactly equal the sum of its items' |
|
values:: |
|
|
|
>>> b = Batch() |
|
>>> b.add_package(i) |
|
Traceback (most recent call last): |
|
... |
|
OptionConflict: Total package weight must be specified when Customs.Items |
|
are used |
|
|
|
>>> b.add_package(i, WeightOz(1)) |
|
Traceback (most recent call last): |
|
... |
|
OptionConflict: Total item weight is 12 oz, but |
|
total package weight is only 1 oz |
|
|
|
>>> b.add_package(i, WeightOz(12), Value(69)) |
|
Traceback (most recent call last): |
|
... |
|
OptionConflict: Can't set 'Value=29.95' when 'Value=69' already set |
|
|
|
And a form type and contents type must be specified if you include any items:: |
|
|
|
>>> b.add_package(i, WeightOz(12)) |
|
Traceback (most recent call last): |
|
... |
|
OptionConflict: Customs form + content type must be specified with items |
|
|
|
>>> b.add_package(i, WeightOz(12), Customs.Gift) |
|
Traceback (most recent call last): |
|
... |
|
OptionConflict: Customs form + content type must be specified with items |
|
|
|
>>> b.add_package(i, WeightOz(12), Customs.CN22) |
|
Traceback (most recent call last): |
|
... |
|
OptionConflict: Customs form + content type must be specified with items |
|
|
|
>>> b.add_package(i, WeightOz(12), Customs.Gift, Customs.CN22) |
|
>>> print b.tostring() |
|
<DAZzle> |
|
<Package ID="1"> |
|
<CustomsQuantity1>1</CustomsQuantity1> |
|
<CustomsCountry1>United States</CustomsCountry1> |
|
<CustomsDescription1>Paperback book</CustomsDescription1> |
|
<CustomsWeight1>12</CustomsWeight1> |
|
<CustomsValue1>29.95</CustomsValue1> |
|
<WeightOz>12</WeightOz> |
|
<ContentsType>GIFT</ContentsType> |
|
<CustomsFormType>CN22</CustomsFormType> |
|
<Value>29.95</Value> |
|
</Package> |
|
</DAZzle> |
|
|
|
The final customs form will include the multiplied-out weights and values based |
|
on the quantity of each item:: |
|
|
|
>>> b = Batch() |
|
>>> b.add_package( |
|
... Customs.Item('x',23,42,3), Customs.Item('y',1,7), |
|
... WeightOz(99), Customs.Gift, Customs.CN22 |
|
... ) |
|
>>> print b.tostring() |
|
<DAZzle> |
|
<Package ID="1"> |
|
<CustomsQuantity1>3</CustomsQuantity1> |
|
<CustomsCountry1>United States</CustomsCountry1> |
|
<CustomsDescription1>x</CustomsDescription1> |
|
<CustomsWeight1>69</CustomsWeight1> |
|
<CustomsValue1>126</CustomsValue1> |
|
<CustomsQuantity2>1</CustomsQuantity2> |
|
<CustomsCountry2>United States</CustomsCountry2> |
|
<CustomsDescription2>y</CustomsDescription2> |
|
<CustomsWeight2>1</CustomsWeight2> |
|
<CustomsValue2>7</CustomsValue2> |
|
<WeightOz>99</WeightOz> |
|
<ContentsType>GIFT</ContentsType> |
|
<CustomsFormType>CN22</CustomsFormType> |
|
<Value>133</Value> |
|
</Package> |
|
</DAZzle> |
|
|
|
|
|
Customs Signature |
|
----------------- |
|
|
|
You can specify the person who's certifying the customs form using these |
|
options:: |
|
|
|
>>> Customs.Signer("Phillip Eby") |
|
CustomsSigner('Phillip Eby') |
|
|
|
>>> Customs.Certify |
|
CustomsCertify('TRUE') |
|
|
ContentsType(), CustomsFormType() |
|
|
|
|
|
Processing Options |
Processing Options |
================== |
================== |
|
|
Test |
XXX DAZzle.Test |
Layout(filename) |
DAZzle.Layout(filename) |
OutputFile(filename) |
DAZzle.OutputFile(filename) |
|
DAZzle.Print |
Print |
DAZzle.Verify |
Verify |
DAZzle.SkipUnverified |
|
DAZzle.AutoClose |
SkipUnverified |
DAZzle.Prompt |
AutoClose |
DAZzle.AbortOnError |
Prompt |
DAZzle.AutoPrintCustomsForms |
AbortOnError |
DAZzle.XMLDirectory |
AutoPrintCustomsForms |
DAZzle.LayoutDirectory |
|
DAZzle.exe_path |
|
|
|
|
Miscellaneous |
Miscellaneous |
============= |
============= |
|
|
RubberStamp(n, text) |
XXX RubberStamp(n, text) |
ReferenceID(text) |
ReferenceID(text) |
CostCenter(int) |
CostCenter(int) |
|
|
Internals and Tests |
Internals and Tests |
------------------- |
------------------- |
|
|
|
Misc imports for tests:: |
|
|
>>> from pydicia import add_to_package, ET, Option, Batch, Package |
>>> from pydicia import add_to_package, ET, Option, Batch, Package |
|
|
Packages:: |
Packages:: |
</Package> |
</Package> |
</DAZzle> |
</DAZzle> |
|
|
>>> p.should_queue(COD) |
>>> p.should_queue(Services.COD) |
True |
True |
>>> print b.tostring() |
>>> print b.tostring() |
<DAZzle Start="DAZ"> |
<DAZzle Start="DAZ"> |
</Package> |
</Package> |
</DAZzle> |
</DAZzle> |
|
|
>>> p.should_queue(COD) |
>>> p.should_queue(Services.COD) |
False |
False |
|
|
|
|
<DAZzle /> |
<DAZzle /> |
|
|
|
|
Misc shipment:: |
Misc shipment and postprocessing:: |
|
|
>>> s = Shipment(verify_zip) |
>>> s = Shipment(verify_zip) |
>>> s.add_package(Box) |
>>> s.add_package(Box) |
</Package> |
</Package> |
</DAZzle> |
</DAZzle> |
|
|
|
|
Option inversion:: |
Option inversion:: |
|
|
>>> ~Envelope |
>>> ~Envelope |
Option('FlatRate', 'FALSE', None) |
FlatRate('FALSE') |
>>> ~~Envelope |
>>> ~~Envelope |
Option('FlatRate', 'TRUE', None) |
FlatRate('TRUE') |
|
|
>>> ~Option('Services', 'ON', 'RegisteredMail') |
>>> ~Option('Services', 'ON', 'RegisteredMail') |
Option('Services', 'OFF', 'RegisteredMail') |
Services.RegisteredMail('OFF') |
>>> ~~Option('Services', 'ON', 'RegisteredMail') |
>>> ~~Option('Services', 'ON', 'RegisteredMail') |
Option('Services', 'ON', 'RegisteredMail') |
Services.RegisteredMail('ON') |
|
|
>>> ~Option('DAZzle', 'YES', 'Prompt') |
>>> ~Option('DAZzle', 'YES', 'Prompt') |
Option('DAZzle', 'NO', 'Prompt') |
DAZzle.Prompt('NO') |
>>> ~~Option('DAZzle', 'YES', 'Prompt') |
>>> ~~Option('DAZzle', 'YES', 'Prompt') |
Option('DAZzle', 'YES', 'Prompt') |
DAZzle.Prompt('YES') |
|
|
|
|
The ``iter_options()`` generic function yields "option" objects for an |
The ``iter_options()`` generic function yields "option" objects for an |