def complete(self, template_id=None): """ Closes a reminder in the draft status (DRAFT). Here, the status of open (OPEN) or overdue (Overdue) is set and a PDF is generated and stored in the file system. The optional paramter template_id determines which template is used to create a pdf. If this parameter is not specified, the default template set is used. """ # Path path = "/api/reminders/{id}/complete".format(id=self.id) # XML complete_tag = ET.Element("complete") if template_id: template_id_tag = ET.Element("template_id") template_id_tag.text = str(template_id) complete_tag.append(template_id_tag) xml = ET.tostring(complete_tag) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Parse response error_text_list = [] for error in ET.fromstring(response.data): error_text_list.append(error.text) # Raise Error raise errors.BillomatError("\n".join(error_text_list))
def complete(self, template_id=None): """ Closes a statement in the draft status (DRAFT) from. The status of open (OPEN) or overdue (Overdue) is set and a PDF is generated and stored in the file system. """ # Path path = "/api/invoices/{id}/complete".format(id=self.id) # XML complete_tag = ET.Element("complete") if template_id: template_id_tag = ET.Element("template_id") template_id_tag.text = str(template_id) complete_tag.append(template_id_tag) xml = ET.tostring(complete_tag) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Parse response error_text_list = [] for error in ET.fromstring(response.data): error_text_list.append(error.text) # Raise Error raise errors.BillomatError("\n".join(error_text_list))
def edit(self, id=None, invoice_id=None, contact_id=None, address=None, date=None, due_date=None, subject=None, label=None, intro=None, note=None, template_id=None): """ Edit a reminder :param id: ID of the reminder :param invoice_id: ID of the overdue invoice :param contact_id: ID of the contact :param address: the address; Default: Address from invoice :param date: Date of the reminder; Default: today :param due_date: Due date of the reminder; Default: date + due days taken from the settings :param subject: Subject; Default: Subject of the next dunning level (if available) :param label: Label text to describe the project :param intro: Introductory text; Default: Introductory text of the next dunning level (if available) :param note: Explanatory notes; Default: Explanatory notes of the next dunning level (if available) :param template_id: ID of template to use. """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _reminder_xml(invoice_id=invoice_id, contact_id=contact_id, address=address, date=date, due_date=due_date, subject=subject, label=label, intro=intro, note=note, template_id=template_id) # Path path = "/api/reminders/{id}".format(id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))
def create(cls, conn, reminder_id, name): """ Creates one reminder-tag :param conn: Connection-Object :param reminder_id: ID of the reminder :param name: Name of the tag """ # XML reminder_tag = ET.Element("reminder-tag") reminder_id_tag = ET.Element("reminder_id") reminder_id_tag.text = unicode(int(reminder_id)) reminder_tag.append(reminder_id_tag) name_tag = ET.Element("name") name_tag.text = unicode(name) reminder_tag.append(name_tag) xml = ET.tostring(reminder_tag) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create Item-Object from XML item_object = cls(conn=conn) item_object.load_from_xml(response.data) # Finished return item_object
def create(cls, conn, invoice_id=None, contact_id=None, address=None, date=None, due_date=None, subject=None, label=None, intro=None, note=None, template_id=None): """ Creates a reminder :param conn: Connection-Object :param invoice_id: ID of the overdue invoice :param contact_id: ID of the contact :param address: the address; Default: Address from invoice :param date: Date of the reminder; Default: today :param due_date: Due date of the reminder; Default: date + due days taken from the settings :param subject: Subject; Default: Subject of the next dunning level (if available) :param label: Label text to describe the project :param intro: Introductory text; Default: Introductory text of the next dunning level (if available) :param note: Explanatory notes; Default: Explanatory notes of the next dunning level (if available) :param template_id: ID of template to use. """ # XML xml = _reminder_xml(invoice_id=invoice_id, contact_id=contact_id, address=address, date=date, due_date=due_date, subject=subject, label=label, intro=intro, note=note) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create Reminder-Object reminder = cls(conn=conn) reminder.content_language = response.headers.get( "content-language", None) reminder.load_from_xml(response.data) # Finished return reminder
def create(cls, conn, credit_note_id=None, article_id=None, unit=None, quantity=None, unit_price=None, tax_name=None, tax_rate=None, title=None, description=None, reduction=None): """ Creates a credit note item :param conn: Connection-Object :param credit_note_id: ID of the credit note :param article_id: ID of the article, sets additionally the values from the article on creation :param unit: Unit :param quantity: Quantity :param unit_price: Price per unit :param tax_name: Name of the tax :param tax_rate: rate of taxation :param title: Title :param description: Description :param reduction: Reduction (absolute or percent: 10/10%) """ # XML xml = _credit_note_item_xml(credit_note_id=credit_note_id, article_id=article_id, unit=unit, quantity=quantity, unit_price=unit_price, tax_name=tax_name, tax_rate=tax_rate, title=title, description=description, reduction=reduction) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create CreditNote-Object credit_note = cls(conn=conn) credit_note.content_language = response.headers.get( "content-language", None) credit_note.load_from_xml(response.data) # Finished return credit_note
def send_snailmail(self, color=None, duplex=None, paper_weight=None, attachments=None): """ Sends the invoice snailmail (Post) to the customer Warning: Pixelletter account needed! :param color=Determines whether to use color printing. :param duplex=Determines whether to use duplex printing. :param paper_weight=Determines the paper weight in grams. :param attachments=Further PDF files. """ # Path path = "{base_path}/{id}/mail".format(base_path=self.base_path, id=self.id) # XML mail_tag = ET.Element("mail") # Color if color: color_tag = ET.Element("color") color_tag.text = color mail_tag.append(color_tag) # Duplex if duplex: duplex_tag = ET.Element("duplex") duplex_tag.text = duplex mail_tag.append(duplex_tag) # Paper_weight if paper_weight: paper_weight_tag = ET.Element("paper_weight") paper_weight_tag.text = paper_weight mail_tag.append(paper_weight_tag) # ToDo: Attachments xml = ET.tostring(mail_tag) # Send POST-request response = self.conn.post(path=path, body=xml) if response.status != 200: # Parse response error_text_list = [] for error in ET.fromstring(response.data): error_text_list.append(error.text) # Raise Error raise errors.BillomatError("\n".join(error_text_list))
def edit(self, id=None, article_id=None, unit=None, quantity=None, unit_price=None, tax_name=None, tax_rate=None, title=None, description=None, reduction=None): """ Edit a credit note item :param id: ID of the credit note item :param article_id: ID of the article, sets additionally the values from the article on creation :param unit: Unit :param quantity: Quantity :param unit_price: Price per unit :param tax_name: Name of the tax :param tax_rate: Rate of taxation :param title: Title :param description: Description :param reduction: Reduction (absolute or percent: 10/10%) """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _credit_note_item_xml(article_id=article_id, unit=unit, quantity=quantity, unit_price=unit_price, tax_name=tax_name, tax_rate=tax_rate, title=title, description=description, reduction=reduction) # Path path = "{base_path}/{id}".format(base_path=self.base_path, id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))
def create(cls, conn, sorting=None, name=None, subject=None, header=None, footer=None, charge_name=None, charge_description=None, charge_amount=None): """ Creates an email template :param conn: Connection-Object :param sorting: The sorting of this reminder text; Without a sorting the reminder text it placed at the end of all reminder texts. :param name: A name for internal use only :param subject: A subject. :param header: Introductory text :param footer: xplanatory notes :param charge_name: Name of charge (if present) :param charge_description: Description of charge (if present) :param charge_amount: Ammount of charge (if present) """ # XML xml = _reminder_text_xml(sorting=sorting, name=name, subject=subject, header=header, footer=footer, charge_name=charge_name, charge_description=charge_description, charge_amount=charge_amount) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create ReminderText-Object reminder_text = cls(conn=conn) reminder_text.content_language = response.headers.get( "content-language", None) reminder_text.load_from_xml(response.data) # Finished return reminder_text
def create(cls, conn, reminder_id=None, article_id=None, unit=None, quantity=None, unit_price=None, title=None, description=None): """ Creates a reminder-item :param conn: Connection-Object :param reminder_id: ID of the reminder :param article_id: ID of the article, sets additionally the values from the article on creation. :param unit: Unit :param quantity: Quantity :param unit_price: Price per unit :param title: Title :param description: Description """ # XML xml = _reminder_item_xml( reminder_id=reminder_id, article_id=article_id, unit=unit, quantity=quantity, unit_price=unit_price, title=title, description=description, ) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create Reminder-Object reminder = cls(conn=conn) reminder.content_language = response.headers.get( "content-language", None) reminder.load_from_xml(response.data) # Finished return reminder
def edit(self, id=None, sorting=None, name=None, subject=None, header=None, footer=None, charge_name=None, charge_description=None, charge_amount=None): """ Edit one email template :param sorting: The sorting of this reminder text; Without a sorting the reminder text it placed at the end of all reminder texts. :param name: A name for internal use only :param subject: A subject. :param header: Introductory text :param footer: xplanatory notes :param charge_name: Name of charge (if present) :param charge_description: Description of charge (if present) :param charge_amount: Ammount of charge (if present) """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _reminder_text_xml(sorting=sorting, name=name, subject=subject, header=header, footer=footer, charge_name=charge_name, charge_description=charge_description, charge_amount=charge_amount) # Path path = "{base_path}/{id}".format(base_path=self.base_path, id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))
def edit( self, id = None, name = None, type = None, subject = None, text = None, bcc = None, is_default = None ): """ Edit one email template :param name: Name of the template; mandatory :param type: Document type; mandatory :param subject: Subject :param text: Message text :param bcc: Specifies whether the sender should get a copy as BCC; boolean; :param is_default: Specifies whether this is the standard template; boolean; """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _email_template_xml( name = name, type = type, subject = subject, text = text, bcc = bcc, is_default = is_default ) # Path path = "{base_path}/{id}".format( base_path = self.base_path, id = self.id ) # Send PUT-request response = self.conn.put(path = path, body = xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding = "utf-8"))
def create( cls, conn, name = None, type = None, subject = None, text = None, bcc = None, is_default = None ): """ Creates an email template :param conn: Connection-Object :param name: Name of the template; mandatory :param type: Document type; mandatory :param subject: Subject :param text: Message text :param bcc: Specifies whether the sender should get a copy as BCC; boolean; :param is_default: Specifies whether this is the standard template; boolean; """ # XML xml = _email_template_xml( name = name, type = type, subject = subject, text = text, bcc = bcc, is_default = is_default ) # Send POST-request response = conn.post(path = cls.base_path, body = xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding = "utf-8")) # Create EmailTemplate-Object email_template = cls(conn = conn) email_template.content_language = response.headers.get("content-language", None) email_template.load_from_xml(response.data) # Finished return email_template
def edit(self, id=None, article_id=None, unit=None, quantity=None, unit_price=None, title=None, description=None): """ Edit a reminder-item :param id: ID of the reminder-item :param article_id: ID of the article, sets additionally the values from the article on creation. :param unit: Unit :param quantity: Quantity :param unit_price: Price per unit :param title: Title :param description: Description """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _reminder_item_xml(article_id=article_id, unit=unit, quantity=quantity, unit_price=unit_price, title=title, description=description) # Path path = "{base_path}/{id}".format(base_path=self.base_path, id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))
def delete(self, id = None): """ Deletes an item """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # Path path = "{base_path}/{id}".format( base_path = self.base_path, id = self.id ) # Fetch data response = self.conn.delete(path = path) if response.status != 200: raise errors.BillomatError(unicode(response.data, encoding = "utf-8"))
def set_customfield(self, value): """ Set *customfield*-value See: http://www.billomat.com/en/api/basics/own-meta-data SET-Property """ # Parameter if value is None: value = u"" # Check essential data if not self.id: raise errors.NoIdError() assert self.base_path != u"/api/<object>" # Path path = "{base_path}/{id}/customfield".format( base_path = self.base_path, id = self.id ) # Keep value in memory self._customfield_value = value # Create XML root_tag_name = self.base_path.rsplit("/", 1)[-1].rstrip("s") root_tag = ET.Element(root_tag_name) customfield_tag = ET.Element("customfield") customfield_tag.text = unicode(value) root_tag.append(customfield_tag) xml = ET.tostring(root_tag) # Send PUT-request response = self.conn.put(path = path, body = xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding = "utf-8"))
def create(cls, conn, client_id, client_property_id, value): """ Creates one Property :param conn: Connection-Object :param client_id: ID of the client :param client_property_id: ID of the property :param value: Property value """ # XML property_tag = ET.Element("client-property-value") client_id_tag = ET.Element("client_id") client_id_tag.text = unicode(int(client_id)) property_tag.append(client_id_tag) client_property_id_tag = ET.Element("client_property_id") client_property_id_tag.text = unicode(int(client_property_id)) property_tag.append(client_property_id_tag) value_tag = ET.Element("value") value_tag.text = unicode(value) property_tag.append(value_tag) xml = ET.tostring(property_tag) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create Property-Object property = cls(conn=conn) property.load_from_xml(response.data) # Finished return property
def edit( self, id = None, type = None, address = None ): """ Edit a recurring-email_receiver :param id: ID of the recurring-email_receiver :param type: Receiver type (to, cc, bcc); mandatory :param address: Email address; mandatory; Empty address resets to the default address. """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _recurring_email_receiver_xml( type = type, address = address ) # Path path = "{base_path}/{id}".format( base_path = self.base_path, id = self.id ) # Send PUT-request response = self.conn.put(path = path, body = xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding = "utf-8"))
def create( cls, conn, recurring_id = None, type = None, address = None ): """ Creates a recurring-email_receiver :param conn: Connection-Object :param recurring_id: ID of the recurring :param type: Receiver type (to, cc, bcc) :param address: Email address """ # XML xml = _recurring_email_receiver_xml( recurring_id = recurring_id, type = type, address = address ) # Send POST-request response = conn.post(path = cls.base_path, body = xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding = "utf-8")) # Create Recurring-Email-Receiver-Object recurring = cls(conn = conn) recurring.content_language = response.headers.get("content-language", None) recurring.load_from_xml(response.data) # Finished return recurring
def edit(self, id=None, client_id=None, label=None, name=None, street=None, zip=None, city=None, state=None, country_code=None, first_name=None, last_name=None, salutation=None, phone=None, fax=None, mobile=None, email=None, www=None): """ Edit a contact-item :param id: ID of the contact-item :param client_id: ID of the client :param label: Label :param name: Company name :param street: Street :param zip: Zip code :param city: City :param state: State, county, district, region :param country_code: Country, Country code as ISO 3166 Alpha-2 Default value: Value from your own company :param first_name: First name :param last_name: Last name :param salutation: Salutation :param phone: Phone :param fax: Fax :param mobile: Mobile Number :param email: Email :param www: Website """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _contact_xml(client_id=client_id, label=label, name=name, street=street, zip=zip, city=city, state=state, country_code=country_code, first_name=first_name, last_name=last_name, salutation=salutation, phone=phone, fax=fax, mobile=mobile, email=email, www=www) # Path path = "{base_path}/{id}".format(base_path=self.base_path, id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))
def create(cls, conn, client_id=None, label=None, name=None, street=None, zip=None, city=None, state=None, country_code=None, first_name=None, last_name=None, salutation=None, phone=None, fax=None, mobile=None, email=None, www=None): """ Creates a contact :param conn: Connection-Object :param client_id: ID of the client :param label: Label :param name: Company name :param street: Street :param zip: Zip code :param city: City :param state: State, county, district, region :param country_code: Country, Country code as ISO 3166 Alpha-2 Default value: Value from your own company :param first_name: First name :param last_name: Last name :param salutation: Salutation :param phone: Phone :param fax: Fax :param mobile: Mobile Number :param email: Email :param www: Website """ # XML xml = _contact_xml(client_id=client_id, label=label, name=name, street=street, zip=zip, city=city, state=state, country_code=country_code, first_name=first_name, last_name=last_name, salutation=salutation, phone=phone, fax=fax, mobile=mobile, email=email, www=www) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create Contact-Object contact = cls(conn=conn) contact.content_language = response.headers.get( "content-language", None) contact.load_from_xml(response.data) # Finished return contact
def search( self, # Search parameters reminder_id=None, order_by=None, fetch_all=False, allow_empty_filter=False, keep_old_items=False, page=1, per_page=None): """ Fills the (internal) list with ReminderTag-objects If no search criteria given --> all tags will returned (REALLY ALL!). :param reminder_id: Reminder ID :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. All reminder-tags will returned. !!! EVERY !!! """ # Check empty filter if not allow_empty_filter: if not any([ reminder_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path="/api/reminder-tags") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if reminder_id: url.query["reminder_id"] = reminder_id # Fetch data response = self.conn.get(path=str(url)) if response.status != 200: # Check if "Unothorized" --> raise NotFoundError errors_etree = ET.fromstring(response.data) for error_etree in errors_etree: text = error_etree.text if text.lower() == "unauthorized": raise errors.NotFoundError( u"reminder_id: {reminder_id}".format( reminder_id=reminder_id)) # Other Error raise errors.BillomatError(response.data) # No response (workaround for inconsistent gziped answer; DecodeError) try: if len(response.data) == 0: return except urllib3.exceptions.DecodeError: if response.headers.get("content-type", "").lower() != "application/xml": return else: raise # Parse XML tags_etree = ET.fromstring(response.data) self.per_page = int(tags_etree.attrib.get("per_page", "0")) self.total = int(tags_etree.attrib.get("total", "0")) self.page = int(tags_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all tags for tag_etree in tags_etree: self.append(ReminderTag(conn=self.conn, tag_etree=tag_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters reminder_id=reminder_id, fetch_all=fetch_all, allow_empty_filter=allow_empty_filter, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters invoice_id = None, from_date = None, to_date = None, type = None, user_id = None, order_by = None, fetch_all = False, allow_empty_filter = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the (internal) list with InvoicePayment-objects If no search criteria given --> all payments will returned (REALLY ALL!). :param invoice_id: ID of the invoice :param from_date: Original "from"; Only payments since this date :param to_date: Original "to"; Only payments up to this date :param type: Payment type (eg. CASH, BANK_TRANSFER, PAYPAL, ...). More than one payment type could be given as a comma separated list. Theses payment types will be logically OR-connected. :param user_id: ID of the user :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. All invoice-payments will returned. !!! EVERY !!! """ # Check empty filter if not allow_empty_filter: if not any([ invoice_id, from_date, to_date, type, user_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/invoice-payments") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if invoice_id: url.query["invoice_id"] = invoice_id if from_date: url.query["from"] = from_date if to_date: url.query["to"] = to_date if type: url.query["type"] = type if user_id: url.query["user_id"] = user_id # Fetch data response = self.conn.get(path = str(url)) if response.status != 200: # Check if "Unothorized" --> raise NotFoundError errors_etree = ET.fromstring(response.data) for error_etree in errors_etree: text = error_etree.text if text.lower() == "unauthorized": raise errors.NotFoundError( u"invoice_id: {invoice_id}".format(invoice_id = invoice_id) ) # Other Error raise errors.BillomatError(response.data) # No response (workaround for inconsistent gziped answer; DecodeError) try: if len(response.data) == 0: return except urllib3.exceptions.DecodeError: if response.headers.get("content-type", "").lower() != "application/xml": return else: raise # Parse XML payments_etree = ET.fromstring(response.data) self.per_page = int(payments_etree.attrib.get("per_page", "0")) self.total = int(payments_etree.attrib.get("total", "0")) self.page = int(payments_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all payments for payment_etree in payments_etree: self.append( InvoicePayment(conn = self.conn, payment_etree = payment_etree) ) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters invoice_id = invoice_id, from_date = from_date, to_date = to_date, type = type, user_id = user_id, order_by = order_by, fetch_all = fetch_all, allow_empty_filter = allow_empty_filter, keep_old_items = True, page = page + 1, per_page = per_page )
def edit( self, id=None, client_id=None, contact_id=None, address=None, number_pre=None, number=None, number_length=None, date=None, supply_date=None, supply_date_type=None, due_date=None, discount_rate=None, discount_days=None, title=None, label=None, intro=None, note=None, reduction=None, currency_code=None, net_gross=None, quote=None, payment_types=None, invoice_id=None, offer_id=None, confirmation_id=None, recurring_id=None, ): """ Edit an invoice :param id: ID of the invoice :param client_id: ID of the client :param contact_id: ID of the contact :param address: the address :param number_pre: invoice number prefix :param number: serial number :param number_length: Minimum length of the invoice number (to be filled with leading zeros) :param date: Invoice date :param supply_date: supply/delivery date; MIXED (DATE/ALNUM) :param supply_date_type: type or supply/delivery date; ALNUM ( "SUPPLY_DATE", "DELIVERY_DATE", "SUPPLY_TEXT", "DELIVERY_TEXT") :param due_date: due date :param discount_rate: Cash discount :param discount_days: Cash discount date :param title: Document title; Let it empty to use the default value from settings: "Invoice [Invoice.invoice_number]" :param label: Label text to describe the project :param intro: Introductory text :param note: Explanatory notes :param reduction: Reduction (absolute or percent: 10/10%) :param currency_code: Currency; ISO currency code :param net_gross: Price basis (gross or net prices) :param quote: Currency quote (for conversion into standard currency) :param payment_types: List (separated by comma) of all accepted payment types. :param invoice_id: The ID of the corrected invoice, if it is an invoice correction. :param offer_id: The ID of the estimate, if the invoice was created from an estimate. :param confirmation_id: The ID of the confirmation, if the invoice was created from a confirmation. :param recurring_id: The ID of the recurring, if the invoice was created from a recurring. """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _invoice_xml(client_id=client_id, contact_id=contact_id, address=address, number_pre=number_pre, number=number, number_length=number_length, date=date, supply_date=supply_date, supply_date_type=supply_date_type, due_date=due_date, discount_rate=discount_rate, discount_days=discount_days, title=title, label=label, intro=intro, note=note, reduction=reduction, currency_code=currency_code, net_gross=net_gross, quote=quote, payment_types=payment_types, invoice_id=invoice_id, offer_id=offer_id, confirmation_id=confirmation_id, recurring_id=recurring_id) # Path path = "/api/invoices/{id}".format(id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))
def create( cls, conn, client_id=None, contact_id=None, address=None, number_pre=None, number=None, number_length=None, date=None, supply_date=None, supply_date_type=None, due_date=None, discount_rate=None, discount_days=None, title=None, label=None, intro=None, note=None, reduction=None, currency_code=None, net_gross=None, quote=None, payment_types=None, invoice_id=None, offer_id=None, confirmation_id=None, recurring_id=None, # invoice_items = None ): """ Creates an invoice :param conn: Connection-Object :param client_id: ID of the client :param contact_id: ID of the contact :param address: the address :param number_pre: invoice number prefix :param number: serial number :param number_length: Minimum length of the invoice number (to be filled with leading zeros) :param date: Invoice date :param supply_date: supply/delivery date; MIXED (DATE/ALNUM) :param supply_date_type: type or supply/delivery date; ALNUM ( "SUPPLY_DATE", "DELIVERY_DATE", "SUPPLY_TEXT", "DELIVERY_TEXT") :param due_date: due date :param discount_rate: Cash discount :param discount_days: Cash discount date :param title: Document title; Let it empty to use the default value from settings: "Invoice [Invoice.invoice_number]" :param label: Label text to describe the project :param intro: Introductory text :param note: Explanatory notes :param reduction: Reduction (absolute or percent: 10/10%) :param currency_code: Currency; ISO currency code :param net_gross: Price basis (gross or net prices) :param quote: Currency quote (for conversion into standard currency) :param payment_types: List (separated by comma) of all accepted payment types. :param invoice_id: The ID of the corrected invoice, if it is an invoice correction. :param offer_id: The ID of the estimate, if the invoice was created from an estimate. :param confirmation_id: The ID of the confirmation, if the invoice was created from a confirmation. :param recurring_id: The ID of the recurring, if the invoice was created from a recurring. # :param invoice_items: List with InvoiceItem-Objects """ # XML xml = _invoice_xml(client_id=client_id, contact_id=contact_id, address=address, number_pre=number_pre, number=number, number_length=number_length, date=date, supply_date=supply_date, supply_date_type=supply_date_type, due_date=due_date, discount_rate=discount_rate, discount_days=discount_days, title=title, label=label, intro=intro, note=note, reduction=reduction, currency_code=currency_code, net_gross=net_gross, quote=quote, payment_types=payment_types, invoice_id=invoice_id, offer_id=offer_id, confirmation_id=confirmation_id, recurring_id=recurring_id) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create Invoice-Object invoice = cls(conn=conn) invoice.content_language = response.headers.get( "content-language", None) invoice.load_from_xml(response.data) # Finished return invoice
def send( self, from_address=None, to_address=None, cc_address=None, bcc_address=None, subject=None, body=None, filename=None, # attachments = None ): """ Sends the invoice per e-mail to the customer :param from_address: (originally: from) Sender :param to_address: (originally: recepients) :param cc_address: (originally: recepients) :param bcc_address: (originally: recepients) :param subject: Subject of the e-mail (may include placeholders) :param body: Text of the e-mail (may include placeholders) :param filename: Name of the PDF file (without .pdf) # :param attachments: List with Dictionaries:: # # [ # { # "filename": "<Filename>", # "mimetype": "<MimeType>", # "base64file": "<Base64EncodedFile>" # }, # ... # ] """ # Path path = "{base_path}/{id}/email".format(base_path=self.base_path, id=self.id) # XML email_tag = ET.Element("email") # From if from_address: from_tag = ET.Element("from") from_tag.text = from_address email_tag.append(from_tag) # Recipients if to_address or cc_address or bcc_address: recipients_tag = ET.Element("recipients") email_tag.append(recipients_tag) # To if to_address: to_tag = ET.Element("to") to_tag.text = to_address recipients_tag.append(to_tag) # Cc if cc_address: cc_tag = ET.Element("cc") cc_tag.text = cc_address recipients_tag.append(cc_tag) # Bcc if bcc_address: bcc_tag = ET.Element("bcc") bcc_tag.text = bcc_address recipients_tag.append(bcc_tag) # Subject if subject: subject_tag = ET.Element("subject") subject_tag.text = subject email_tag.append(subject_tag) # Body if body: body_tag = ET.Element("body") body_tag.text = body email_tag.append(body_tag) # Filename if filename: filename_tag = ET.Element("filename") filename_tag.text = filename filename_tag.append(filename_tag) # ToDo: Attachments xml = ET.tostring(email_tag) # Send POST-request response = self.conn.post(path=path, body=xml) if response.status != 200: # Parse response error_text_list = [] for error in ET.fromstring(response.data): error_text_list.append(error.text) # Raise Error raise errors.BillomatError("\n".join(error_text_list))
def edit(self, id=None, archived=None, number_pre=None, number=None, number_length=None, name=None, street=None, zip=None, city=None, state=None, country_code=None, first_name=None, last_name=None, salutation=None, phone=None, fax=None, mobile=None, email=None, www=None, tax_number=None, vat_number=None, bank_account_number=None, bank_account_owner=None, bank_number=None, bank_name=None, bank_swift=None, bank_iban=None, sepa_mandate=None, sepa_mandate_date=None, tax_rule=None, net_gross=None, default_payment_types=None, note=None, discount_rate_type=None, discount_rate=None, discount_days_type=None, discount_days=None, due_days_type=None, due_days=None, reminder_due_days_type=None, reminder_due_days=None, offer_validity_days_type=None, offer_validity_days=None, currency_code=None, price_group=None, locale=None): """ Edit one client :param archived: State of archival storage. True = archived, False = active Default value: False :param number_pre: Prefix Default value: Value from settings :param number: sequential number Default value: next free number :param number_length: Minimum length of the customer number (to be filled with leading zeros) Default value: Value from settings :param name: Company name :param street: Street :param zip: Zip code :param city: City :param state: State, county, district, region :param country_code: Country, Country code as ISO 3166 Alpha-2 Default value: Value from your own company :param first_name: First name :param last_name: Last name :param salutation: Salutation :param phone: Phone :param fax: Fax :param mobile: Mobile number :param email: Email, valid Email address :param www: Website, URL (w/o http) :param tax_number: Tax number :param vat_number: VAT number, valid VAT number :param bank_account_number: Bank account number :param bank_account_owner: Bank account owner :param bank_number: Bank identifier code :param bank_name: Bank name :param bank_swift: SWIFT/BIC :param bank_iban: IBAN :param sepa_mandate: Mandate reference of a SEPA Direct Debit mandate :param sepa_mandate_date: Date of issue of the SEPA Direct Debit mandate :param tax_rule: Tax Rule Possible values: TAX, NO_TAX, COUNTRY Default value: "COUNTRY" :param default_payment_types: Payment Type(s) (eg. CASH, BANK_TRANSFER, PAYPAL, ...). More than one payment type could be given as a comma separated list. Theses payment types will be logically OR-connected. You can find a overview of all payment types at API documentation of payments. If no value is passed, the customer will be offered the payment types specified at the account settings. :param net_gross: Price basis (net, gross, according to account settings) Possible values: NET, GROSS, SETTINGS Default value: "SETTINGS" :param note: Note :param discount_rate_type: Type of the default value for discount rate Possible values: SETTINGS, ABSOLUTE, RELATIVE Default value: "SETTINGS" :param discount_rate: Discount rate :param discount_days_type: Type of the default value for discount interval Possible values: SETTINGS, ABSOLUTE, RELATIVE Default value: "SETTINGS" :param discount_days: Discount period in days :param due_days_type: Type of the default value for maturity Possible values: SETTINGS, ABSOLUTE, RELATIVE Default value: "SETTINGS" :param due_days: Maturity in days from invoice date :param reminder_due_days_type: Type of the default value for reminder maturity Possible values: SETTINGS, ABSOLUTE, RELATIVE Default value: "SETTINGS" :param reminder_due_days: Reminder maturity :param offer_validity_days_type: Type of the default value for validity of estimates Possible values: SETTINGS, ABSOLUTE, RELATIVE Default value: "SETTINGS" :param offer_validity_days: Validity of estimates :param currency_code: The currency for this client. ISO currency code. If this field is empty, the account currency is used. :param price_group: Artciles can have several prices. The pricegroup defines which price applies to the client. :param locale: Locale of the client. If no value is passed, the locale of the account will be applied to the client. """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _client_xml(archived=archived, number_pre=number_pre, number=number, number_length=number_length, name=name, street=street, zip=zip, city=city, state=state, country_code=country_code, first_name=first_name, last_name=last_name, salutation=salutation, phone=phone, fax=fax, mobile=mobile, email=email, www=www, tax_number=tax_number, vat_number=vat_number, bank_account_number=bank_account_number, bank_account_owner=bank_account_owner, bank_number=bank_number, bank_name=bank_name, bank_swift=bank_swift, bank_iban=bank_iban, sepa_mandate=sepa_mandate, sepa_mandate_date=sepa_mandate_date, tax_rule=tax_rule, net_gross=net_gross, default_payment_types=default_payment_types, note=note, discount_rate_type=discount_rate_type, discount_rate=discount_rate, discount_days_type=discount_days_type, discount_days=discount_days, due_days_type=due_days_type, due_days=due_days, reminder_due_days_type=reminder_due_days_type, reminder_due_days=reminder_due_days, offer_validity_days_type=offer_validity_days_type, offer_validity_days=offer_validity_days, currency_code=currency_code, price_group=price_group, locale=locale) # Path path = "{base_path}/{id}".format(base_path=self.base_path, id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))
def create( cls, conn, client_id=None, # int contact_id=None, # int address=None, number_pre=None, number=None, # int number_length=None, # int date=None, # date title=None, label=None, intro=None, note=None, reduction=None, currency_code=None, net_gross=None, quote=None, # float invoice_id=None # int # credit_note_items = None ): """ Creates a credit note :param conn: Connection-Object :param client_id: ID of the client :param contact_id: ID of the contact :param address: the address :param number_pre: credit note number prefix :param number: serial number :param number_length: Minimum length of the credit note number (to be filled with leading zeros) :param date: Credit-note date :param title: Document title; Let it empty to use the default value from settings :param label: Label text to describe the project :param intro: Introductory text :param note: Explanatory notes :param reduction: Reduction (absolute or percent: 10/10%) :param currency_code: Currency; ISO currency code :param net_gross: Price basis (gross or net prices) :param quote: Currency quote (for conversion into standard currency) :param invoice_id: The ID of the invoice, if the credit note was created from an invoice. # :param invoice_items: List with CreditNoteItem-Objects """ # XML xml = _credit_note_xml( client_id=client_id, # int contact_id=contact_id, # int address=address, number_pre=number_pre, number=number, # int number_length=number_length, # int date=date, # date title=title, label=label, intro=intro, note=note, reduction=reduction, currency_code=currency_code, net_gross=net_gross, quote=quote, # float invoice_id=invoice_id # int ) # Send POST-request response = conn.post(path=cls.base_path, body=xml) if response.status != 201: # Created raise errors.BillomatError(unicode(response.data, encoding="utf-8")) # Create CreditNote-Object credit_note = cls(conn=conn) credit_note.content_language = response.headers.get( "content-language", None) credit_note.load_from_xml(response.data) # Finished return credit_note
def edit( self, id=None, client_id=None, # int contact_id=None, # int address=None, number_pre=None, number=None, # int number_length=None, # int date=None, # date title=None, label=None, intro=None, note=None, reduction=None, currency_code=None, net_gross=None, quote=None, # float invoice_id=None # int ): """ Edit an invoice :param id: ID of the invoice :param client_id: ID of the client :param contact_id: ID of the contact :param address: the address :param number_pre: credit note number prefix :param number: serial number :param number_length: Minimum length of the credit note number (to be filled with leading zeros) :param date: Credit-note date :param title: Document title; Let it empty to use the default value from settings :param label: Label text to describe the project :param intro: Introductory text :param note: Explanatory notes :param reduction: Reduction (absolute or percent: 10/10%) :param currency_code: Currency; ISO currency code :param net_gross: Price basis (gross or net prices) :param quote: Currency quote (for conversion into standard currency) :param invoice_id: The ID of the invoice, if the credit note was created from an invoice. """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _credit_note_xml( client_id=client_id, # int contact_id=contact_id, # int address=address, number_pre=number_pre, number=number, # int number_length=number_length, # int date=date, # date title=title, label=label, intro=intro, note=note, reduction=reduction, currency_code=currency_code, net_gross=net_gross, quote=quote, # float invoice_id=invoice_id # int ) # Path path = "{base_path}/{id}".format(base_path=self.base_path, id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))
def edit(self, id=None, client_id=None, contact_id=None, title=None, address=None, supply_date=None, supply_date_type=None, due_days=None, discount_rate=None, discount_days=None, name=None, label=None, intro=None, note=None, currency_code=None, reduction=None, net_gross=None, quote=None, payment_types=None, action=None, cycle_number=None, cycle=None, hour=None, start_date=None, end_date=None, next_creation_date=None, email_sender=None, email_subject=None, email_message=None, email_filename=None, email_template_id=None, offer_id=None, confirmation_id=None, template_id=None): """ Edit a recurring :param id: ID of the recurring :param client_id: ID of the client :param contact_id: ID of the contact :param title: Document title; Let it empty to use the default value from settings: "Invoice [Invoice.invoice_number]" :param address: the address; Pass an empty value to use the current customer address. :param supply_date: supply/delivery date; MIXED (DATE/ALNUM) :param supply_date_type: type or supply/delivery date; ALNUM ( "SUPPLY_DATE", "DELIVERY_DATE", "SUPPLY_TEXT", "DELIVERY_TEXT") :param due_days: Due days :param discount_rate: Cash discount :param discount_days: Cash discount days :param name: Name of the recurring; is the title of the recurring :param label: Label text to describe the project :param intro: Introductory text; Default value taken from the settings :param note: Explanatory notes; Default value taken from the settings :param reduction: Reduction (absolute or percent: 10/10%) :param currency_code: Currency; ISO currency code :param net_gross: Price basis (gross or net prices) :param quote: Currency quote (for conversion into standard currency) :param payment_types: List (separated by comma) of all accepted payment types. :param action: Action to be executed (CREATE, COMPLETE, EMAIL) :param cycle_number: Number of intervals. For example, 3 for "every 3 months" :param cycle: Interval (DAILY, WEEKLY, MONTHLY, YEARLY) :param hour: Time of Day (hour) :param start_date: Start date; :param end_date: End date :param next_creation_date: Date of the next creation; Put "" (empty string) to set recurring inactive. :param email_sender: Sender when sending e-mail. If you pass an empty value, the sender will be used from the settings. :param email_subject: Subject when sending e-mail. If you pass an empty value, the subject will be used from the settings. :param email_message: Message text when sending e-mail. If you pass an empty value, the message will be used from the settings. :param email_filename: Filename of the invoice when sending e-mail. If you pass an empty value, the filename will be used from the settings. :param email_template_id: Email template ID :param offer_id: The ID of the estimate, if the recurring was created from an estimate. :param confirmation_id: The ID of the confirmation, if the recurring was created from a confirmation. :param template_id: Template ID """ # Parameters if id: self.id = id if not self.id: raise errors.NoIdError() # XML xml = _recurring_xml(client_id=client_id, contact_id=contact_id, title=title, address=address, supply_date=supply_date, supply_date_type=supply_date_type, due_days=due_days, discount_rate=discount_rate, discount_days=discount_days, name=name, label=label, intro=intro, note=note, currency_code=currency_code, reduction=reduction, net_gross=net_gross, quote=quote, payment_types=payment_types, action=action, cycle_number=cycle_number, cycle=cycle, hour=hour, start_date=start_date, end_date=end_date, next_creation_date=next_creation_date, email_sender=email_sender, email_subject=email_subject, email_message=email_message, email_filename=email_filename, email_template_id=email_template_id, offer_id=offer_id, confirmation_id=confirmation_id, template_id=template_id) # Path path = "/api/recurrings/{id}".format(id=self.id) # Send PUT-request response = self.conn.put(path=path, body=xml) if response.status != 200: # Edited raise errors.BillomatError(unicode(response.data, encoding="utf-8"))