[Subversion] / PyDicia / pydicia.py  

Diff of /PyDicia/pydicia.py

Parent Directory | Revision Log

version 2321, Wed Jul 4 17:13:50 2007 UTC version 2322, Wed Jul 4 18:29:37 2007 UTC
Line 1 
Line 1 
 import os  import os
   from decimal import Decimal
 from simplegeneric import generic  from simplegeneric import generic
 from peak.util.decorators import struct  from peak.util.decorators import struct
   
 try:  try:
     import xml.etree.cElementTree as ET      import xml.etree.cElementTree as ET
 except ImportError:  except ImportError:
Line 10 
Line 12 
         import elementtree.ElementTree as ET          import elementtree.ElementTree as ET
   
 __all__ = [  __all__ = [
     'Option', 'OptionConflict', 'Layout', 'OutputFile', 'Insurance',      'Option', 'OptionConflict', 'Shipment', 'Batch', 'iter_options',
     'DateAdvance', 'Today', 'Tomorrow',  'WeekendDelivery', 'HolidayDelivery',      'DAZzle', 'Services', 'Domestic', 'International', 'Customs',
     'NoPostage', 'Domestic', 'International', 'Shipment', 'Postcard',      'Insurance', 'DateAdvance', 'Today', 'Tomorrow',
     'Envelope', 'Flat', 'RectangularParcel', 'NonRectangularParcel',      'WeekendDelivery', 'HolidayDelivery', 'NoPostage',
     'FlatRateEnvelope', 'FlatRateBox', 'ToAddress', 'ReturnAddress',      'Postcard', 'Envelope', 'Flat', 'RectangularParcel',
     'RubberStamp', 'Print', 'Verify', 'Batch', 'iter_options',      'NonRectangularParcel', 'FlatRateEnvelope', 'FlatRateBox',
       'ToAddress', 'ReturnAddress', 'RubberStamp',
     # ...and many more symbols added dynamically!      # ...and many more symbols added dynamically!
 ]  ]
   
Line 33 
Line 36 
     for ob in ob:      for ob in ob:
         yield ob          yield ob
   
 @generic  
 def add_to_package(ob, package, isdefault):  
     """Update `etree` to apply document info"""  
     for ob in iter_options(ob):  
         add_to_package(ob, package, isdefault)  
   
 class Package:  class Package:
     """The XML for a single package/label"""      """The XML for a single package/label"""
     finished = False      finished = False
       total_items = total_weight = total_value = 0
   
     def __init__(self, batch):      def __init__(self, batch):
         parent = batch.etree          parent = batch.etree
Line 72 
Line 73 
             el.text = unicode(value)              el.text = unicode(value)
   
     def should_queue(self, data):      def should_queue(self, data):
         if self.finished: return False          if self.finished:
               return False
         self.queue.append(data)          self.queue.append(data)
         return True          return True
   
   
   
       def add_customs_item(self, item):
           self.total_items += 1
           self.total_value += item.value * item.qty
           self.total_weight += item.weight * item.qty
           n = str()
           add_to_package(
               NumberedOptions(self.total_items,
                   CustomsWeight = item.weight * item.qty,
                   CustomsDescription = item.desc,
                   CustomsQuantity = item.qty,
                   CustomsValue = item.value * item.qty,
                   CustomsCountry = item.origin
               ), self, False
           )
   
     def finish(self):      def finish(self):
         self.finished = True          self.finished = True
         for item in self.queue: add_to_package(item, self, False)  
           for item in self.queue:
               add_to_package(item, self, False)
   
           if self.total_items:
               add_to_package(Value(self.total_value), self, False)
               from decimal import Decimal
               if self['WeightOz', None] is None:
                   raise OptionConflict(
                       "Total package weight must be specified when"
                       " Customs.Items are used"
                   )
               oz = Decimal(self['WeightOz', None])
               if oz < self.total_weight:
                   raise OptionConflict(
                       "Total item weight is %s oz, but total package weight is"
                       " only %s oz" % (self.total_weight, oz)
                   )
               if not self['CustomsFormType',None]or not self['ContentsType',None]:
                   raise OptionConflict(
                       "Customs form + content type must be specified with items"
                   )
   
   
 class Batch:  class Batch:
     """An XML document and its corresponding package objects"""      """An XML document and its corresponding package objects"""
Line 142 
Line 183 
         self.batches.append(batch)          self.batches.append(batch)
   
   
   @generic
   def add_to_package(ob, package, isdefault):
       """Update `etree` to apply document info"""
       for ob in iter_options(ob):
           add_to_package(ob, package, isdefault)
   
   
   
Line 177 
Line 218 
   
     def clone(self, value):      def clone(self, value):
         return Option(self.tag, value, self.attr)          return Option(self.tag, value, self.attr)
       __call__ = clone
     def set(self, package, isdefault=False):      def set(self, package, isdefault=False):
         old = package[self.tag, self.attr]          old = package[self.tag, self.attr]
         if old is not None and old<>unicode(self.value):          if old is not None and old<>unicode(self.value):
Line 192 
Line 233 
         if self.value is not None:          if self.value is not None:
             package[self.tag, self.attr] = self.value              package[self.tag, self.attr] = self.value
   
       def __repr__(self):
           if self.attr:
               return "%s.%s(%r)" % (self.tag, self.attr, self.value)
           return "%s(%r)" % (self.tag, self.value)
   
 @struct(OptionBase)  @struct(OptionBase, __repr__ = OptionBase.__repr__.im_func)
 def Option(tag, value=None, attr=None):  def Option(tag, value=None, attr=None):
     """Object representing DAZzle XML text or attributes"""      """Object representing DAZzle XML text or attributes"""
     return tag, value, attr      return tag, value, attr
   
 add_to_package.when_type(Option)(Option.set)  
   
   
   
   add_to_package.when_type(Option)(Option.set)
   
 def _make_symbols(d, nattr, names, factory=Option, **kw):  def _make_symbols(d, nattr, names, factory=Option, **kw):
     for name in names:      for name in names:
Line 213 
Line 256 
     __all__.extend(names)      __all__.extend(names)
   
 _make_globals(  _make_globals(
     'attr', """  
     Prompt AbortOnError Test SkipUnverified AutoClose AutoPrintCustomsForms  
     """.split(), tag='DAZzle', value='YES'  
 )  
 _make_globals(  
     'attr', """  
     RegisteredMail InsuredMail CertifiedMail RestrictedDelivery ReturnReceipt  
     CertificateOfMailing DeliveryConfirmation SignatureConfirmation COD  
     """.split(), tag='Services', value='ON'  
 )  
 _make_globals(  
     'tag', """      'tag', """
     ReplyPostage BalloonRate NonMachinable OversizeRate Stealth SignatureWaiver      ReplyPostage BalloonRate NonMachinable OversizeRate Stealth SignatureWaiver
     NoWeekendDelivery NoHolidayDelivery ReturnToSender CustomsCertify      NoWeekendDelivery NoHolidayDelivery ReturnToSender CustomsCertify
     """.split(), value='TRUE'      """.split(), value='TRUE'
 )  )
   
 WeekendDelivery = ~NoWeekendDelivery  
 HolidayDelivery = ~NoHolidayDelivery  
   
   
   
   
   
   
   
   
   
   
   
   
 _make_globals(  _make_globals(
     'tag', """      'tag', """
     ToName ToTitle ToCompany ToCity ToState ToPostalCode ToZIP4 ToCountry      ToName ToTitle ToCompany ToCity ToState ToPostalCode ToZIP4 ToCountry
     ToCarrierRoute ToReturnCode ToEmail ToPhone EndorsementLine ReferenceID      ToCarrierRoute ToReturnCode ToEmail ToPhone EndorsementLine ReferenceID
     ToDeliveryPoint Description MailClass PackageType      ToDeliveryPoint Description MailClass PackageType
     ContentsType CustomsFormType      ContentsType CustomsFormType CustomsSigner
   
     WeightOz Width Length Depth CostCenter Value      WeightOz Width Length Depth CostCenter Value
     """.split(), lambda tag: Option(tag).clone      """.split(), lambda tag: Option(tag).clone
 )  )
   
 NoPostage = MailClass('NONE')  NoPostage = MailClass('NONE')
 InsuredMail = Option('Services', None, 'InsuredMail').clone  WeekendDelivery = ~NoWeekendDelivery
   HolidayDelivery = ~NoHolidayDelivery
   
   def NumberedOptions(n, **kw):
       n = str(n)
       return [Option(k+n, v)for k, v in kw.items()]
   
   
 def Layout(filename):  
     """Return an option specifying the desired layout"""  
     return Option('DAZzle', os.path.abspath(filename), 'Layout')  
   
 def OutputFile(filename):  
     """Return an option specifying the desired layout"""  
     return Option('DAZzle', os.path.abspath(filename), 'OutputFile')  class Services:
       _make_symbols(
           locals(), 'attr', """
           RegisteredMail InsuredMail CertifiedMail RestrictedDelivery ReturnReceipt
           CertificateOfMailing DeliveryConfirmation SignatureConfirmation COD
           """.split(), tag='Services', value='ON'
       )
   
 class Insurance:  class Insurance:
     UPIC = InsuredMail('UPIC')      UPIC = Services.InsuredMail('UPIC')
     Endicia = InsuredMail('ENDICIA')      Endicia = Services.InsuredMail('ENDICIA')
     USPS = InsuredMail('ON')      USPS = Services.InsuredMail
     NONE = ~USPS      NONE = ~USPS
   
 def ToAddress(*lines):  def ToAddress(*lines):
     assert len(lines)<=6      assert len(lines)<=6
     return [Option('ToAddress'+str(n+1), v) for n, v in enumerate(lines)]      return [NumberedOptions(n+1, ToAddress=v)[0] for n, v in enumerate(lines)]
   
 def ReturnAddress(*lines):  def ReturnAddress(*lines):
     assert len(lines)<=6      assert len(lines)<=6
     return [Option('ReturnAddress'+str(n+1), v) for n, v in enumerate(lines)]      return [NumberedOptions(n+1, ReturnAddress=v)[0] for n, v in enumerate(lines)]
   
 def RubberStamp(n, text):  def RubberStamp(n, text):
     assert 1<=n<=50      assert 1<=n<=50
     return Option('RubberStamp'+str(n), text)      return Option('RubberStamp'+str(n), text)
   
   Postcard             = PackageType('POSTCARD')
   Envelope             = PackageType('ENVELOPE')
   Flat                 = PackageType('FLAT')
   RectangularParcel    = PackageType('RECTPARCEL')
   NonRectangularParcel = PackageType('NONRECTPARCEL')
   FlatRateEnvelope     = PackageType('FLATRATEENVELOPE')
   FlatRateBox          = PackageType('FLATRATEBOX')
   
   
   
   
   
   
   
   
   class DAZzle:
       _make_symbols(
           locals(), 'attr', """
           Prompt AbortOnError Test SkipUnverified AutoClose AutoPrintCustomsForms
           """.split(), tag='DAZzle', value='YES'
       )
       @staticmethod
       def Layout(filename):
           """Return an option specifying the desired layout"""
           return Option('DAZzle', os.path.abspath(filename), 'Layout')
       @staticmethod
       def OutputFile(filename):
           """Return an option specifying the desired layout"""
           return Option('DAZzle', os.path.abspath(filename), 'OutputFile')
   
       Start  = Option('DAZzle', attr='Start').clone
       Print  = Start('PRINTING')
       Verify = Start('DAZ')
   
 class Domestic:  class Domestic:
     FirstClass = MailClass('FIRST')      FirstClass = MailClass('FIRST')
Line 303 
Line 363 
     GXG        = MailClass('INTLGXG')      GXG        = MailClass('INTLGXG')
     GXGNoDoc   = MailClass('INTLGXGNODOC')      GXGNoDoc   = MailClass('INTLGXGNODOC')
   
 Postcard             = PackageType('POSTCARD')  
 Envelope             = PackageType('ENVELOPE')  
 Flat                 = PackageType('FLAT')  
 RectangularParcel    = PackageType('RECTPARCEL')  
 NonRectangularParcel = PackageType('NONRECTPARCEL')  
 FlatRateEnvelope     = PackageType('FLATRATEENVELOPE')  
 FlatRateBox          = PackageType('FLATRATEBOX')  
   
 def DateAdvance(days):  def DateAdvance(days):
     """Return an option for the number of days ahead of time we're mailing"""      """Return an option for the number of days ahead of time we're mailing"""
     if not isinstance(days, int) or not (0<=days<=30):      if not isinstance(days, int) or not (0<=days<=30):
         raise ValueError("DateAdvance() must be an integer from 0-30")          raise ValueError("DateAdvance() must be an integer from 0-30")
     return Option('DateAdvance', str(days))      return Option('DateAdvance', days)
   
 Today = DateAdvance(0)  Today = DateAdvance(0)
 Tomorrow = DateAdvance(1)  Tomorrow = DateAdvance(1)
   
 Print  = Option('DAZzle', 'PRINTING', 'Start')  
 Verify = Option('DAZzle', 'DAZ',      'Start')  
   
   
   
   
 class Customs:  class Customs:
     _make_symbols(      _make_symbols(
Line 336 
Line 387 
         lambda value: ContentsType(value.upper())          lambda value: ContentsType(value.upper())
     )      )
   
     Signer  = Option('CustomsSigner').clone      Signer  = CustomsSigner
     Certify = Option('CustomsCertify', 'TRUE')      Certify = CustomsCertify
   
     @struct()      @struct()
     def Item(desc, weight, value, qty=1, origin='United States'):      def Item(desc, weight, value, qty=1, origin='United States'):
Line 347 
Line 398 
         assert qty==int(qty)          assert qty==int(qty)
         return desc, Decimal(weight), Decimal(value), int(qty), origin          return desc, Decimal(weight), Decimal(value), int(qty), origin
   
       @add_to_package.when_type(Item)
       def _add_item(ob, package, isdefault):
           assert not isdefault, "Customs.Item objects can't be defaults"
           package.add_customs_item(ob)
   
   
   
   
   
   
   
   
   
   
   
   
   


Generate output suitable for use with a patch program
Legend:
Removed from v.2321  
changed lines
  Added in v.2322

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help