Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 140 additions & 75 deletions tfsoffice/resources/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,12 @@ def save_entries_as_bundle(self, entries, images=[], bundle_prefix='AI', locatio
for e in entries:
e['stamp_no'] = res['StampNo']

year = list(set([re.sub(r'-\d\d-\d\d', '', e['date']) for e in entries]))
if len(year) > 1:
years = list(set([re.sub(r'-\d\d-\d\d', '', e['date']) for e in entries]))

if len(years) > 1:
raise ValueError('Multiple years found in entries')
year = int(year[0])

year = int(years[0])

data = dict(
allow_difference=True,
Expand All @@ -197,25 +199,29 @@ def save_entries_as_bundle(self, entries, images=[], bundle_prefix='AI', locatio
bundle_name='{} {}'.format(bundle_prefix, datetime.datetime.today().isoformat()),
entries=entries,
location=location,
year=year,
transaction_type_no=transaction_type_no,
)

if bundle_name:
data['bundle_name'] = bundle_name

return self.save_bundle_list(data)
bundle = self.create_bundle(data, year)
bundles = [bundle]

bundlelist = self.create_bundlelist(data, bundles, years)

return self.save_bundle_list(bundlelist)

def save_entries_to_ledger(self, entries, images=[], bundle_prefix='AI', location='Journal', bundle_name=None, transaction_type_no=1):
def save_entries_to_ledger(self, entries, images=[], bundle_prefix='AI', location='Journal', bundle_name=None, transaction_type_no=1, prohibit_multiple_years=True):
if images:
res = self._client.attachment.upload_files(images, location=location)
for e in entries:
e['stamp_no'] = res['StampNo']

year = list(set([re.sub(r'-\d\d-\d\d', '', e['date']) for e in entries]))
if len(year) > 1:
years = list(set([self.get_entry_year(e) for e in entries]))

if len(years) > 1 and prohibit_multiple_years:
raise ValueError('Multiple years found in entries')
year = int(year[0])

data = dict(
allow_difference=False,
Expand All @@ -224,14 +230,28 @@ def save_entries_to_ledger(self, entries, images=[], bundle_prefix='AI', locatio
bundle_name='{} {}'.format(bundle_prefix, datetime.datetime.today().isoformat()),
entries=entries,
location=location,
year=year,
transaction_type_no=transaction_type_no,
)

if bundle_name:
data['bundle_name'] = bundle_name

return self.save_bundle_list(data)
if prohibit_multiple_years:
# bundles has just one bundle
year = years[0]
bundle = self.create_bundle(data, year)
bundles = [bundle]

bundlelist = self.create_bundlelist(data, bundles, years)

return self.save_bundle_list(bundlelist)
else:
# collect each created bundle while iterating over years
bundles = list([self.create_bundle(data, year) for year in years])

bundlelist = self.create_bundlelist(data, bundles, years)

return self.save_bundle_list(bundlelist)

def print_entries(self, entries):
accounts = self._client.accounts.get_taxcode_list()['results']
Expand All @@ -241,88 +261,71 @@ def print_entries(self, entries):
vat_account = account_list[str(row['tax_no'])]
print((row['comment'][:40].ljust(40), row['amount'], row['tax_no'], vat_account['AccountNo']))

def create_bundlelist(self, data):
api = self._client._get_client(self._service)
def get_entry_year(self, entry):
date = entry.get('date', None)

if len(data.get('entries', [])) == 0:
raise Exception('No entried found.')
if date is None:
return datetime.datetime.today().year
else:
year_as_string = re.sub(r'-\d\d-\d\d', '', date)
return int(year_as_string)

entries = data.get('entries', [])
def select_entries_for_year(self, entries, year):
return [e for e in entries if self.get_entry_year(e) == year]

def partition_entries_by_invoice_stamp_no(self, entries):
entry_lists = []

# group entries by stamp_no to get unique invoices
invoices = []
for stamp_no in set([e.get('stamp_no', None) for e in entries]):
invoices.append(
entry_lists.append(
[e for e in entries if e.get('stamp_no', None) == stamp_no]
)

#
# Add CurrencyRate to entries
#
try:
rate_res = self._client.client.get_currency_list()
if rate_res['count'] >= 1:
rates = dict([(x['Symbol'], x['Rate']) for x in rate_res['results']])
for entry in entries:
entry['currency_rate'] = rates.get(entry['currency_id'], None) or None

except Exception as ex:
print('ERROR getting currency_rate: %s' % ex)

#
# BUNDLE LIST
#
bundlelist = api.factory.create('BundleList')

bundlelist.Bundles = api.factory.create('ArrayOfBundle')

# Allow difference in credit/debit balance.
# This is only applicable when saving journal data (see SaveOption) below.
# Default value is false.
bundlelist.AllowDifference = data.get('allow_difference', True)
return entry_lists

# DirectLedger
# If set to false use customer ledger. If set to true use account that is set directly.
bundlelist.DirectLedger = data.get('direct_ledger', False)

# SaveOption
# Can be either 1 or 0.
# Setting 1 saves the bundle as a journal which can then be reviewed and edited on the 24SevenOffice web site.
# Setting 0 saves the bundle directly to the ledger.
bundlelist.SaveOption = data.get('save_option', 1)
def create_bundle(self, data, year):
api = self._client._get_client(self._service)

# Attachments
# attachments = {}

# cached stamp
# cache_stamp = None

transaction_numbers = []

#
# BUNDLE
#
bundle = api.factory.create('Bundle')
bundle.Vouchers = api.factory.create('ArrayOfVoucher')

# The YearId is set to the current year of the bundle. e.g. 2017.
bundle.YearId = int(data.get('year', datetime.datetime.today().year))
bundle.YearId = year or int(datetime.datetime.today().year)
# Can be defined for either Bundle or Voucher. This is an entry type.
# The No property from GetTransactionTypes is used.
bundle.Sort = int(data.get('transaction_type_no', 1))

# The name of the bundle.
bundle.Name = data.get('bundle_name', None)

# BundleDirectAccounting: If set to false it automatically calculates VAT. If set to true it does not calculate VAT.
# BundleDirectAccounting:
# This is only applicable when saving journal data (see SaveOption).
if bundlelist.SaveOption:
#
# - If set to false it automatically calculates VAT.
# (here, `save_option` is 0 when direct-to-ledger)
#
# - If set to true it does not calculate VAT.
# (when not direct-to-ledger, bundle.BundleDirectAccounting is not set here)
if data.get('save_option', 1) == 1:
bundle.BundleDirectAccounting = False

# Get the next available TransactionNo
entries_as_flat_list = data.get('entries', [])
all_entries_in_year = self.select_entries_for_year(entries_as_flat_list, bundle.YearId)
entries_in_year_by_invoice = self.partition_entries_by_invoice_stamp_no(all_entries_in_year)

# Get the next available TransactionNo, within a given year
entry_id = api.factory.create('EntryId')
today = datetime.datetime.today()
entry_id.Date = datetime.datetime(data['year'], today.month, today.day)
entry_id.Date = datetime.datetime(bundle.YearId, today.month, today.day)
entry_id.SortNo = 3 # incoming invoice/creditnote
entry_id.EntryNo = 1 # temp value
entry_id = api.service.GetEntryId(entry_id)
Expand All @@ -332,10 +335,10 @@ def create_bundlelist(self, data):
#
# invoice_refs = list(set([entry['invoice_refno'] for entry in entries]))

for pos, invoice in enumerate(invoices):
for pos, entries_in_year_for_invoice in enumerate(entries_in_year_by_invoice):

#
# VOUCHER / invoice
# VOUCHER / invoice entries in given year / transaction
#
# This the transaction number of the voucher.
voucher = api.factory.create('Voucher')
Expand All @@ -347,9 +350,8 @@ def create_bundlelist(self, data):
voucher.Sort = int(data.get('transaction_type_no', 1))

voucher.TransactionNo = entry_id.EntryNo + pos
transaction_numbers.append(voucher.TransactionNo)

for row in invoice:
for row in entries_in_year_for_invoice:
#
# ENTRY / a single transaction
#
Expand Down Expand Up @@ -387,32 +389,95 @@ def create_bundlelist(self, data):
# add voucher to bundle
bundle.Vouchers.Voucher.append(voucher)

# add bundle to bundlelist
bundlelist.Bundles.Bundle.append(bundle)
return bundlelist
return bundle


def save_bundle_list(self, data):
def create_bundlelist(self, data, bundles, years):
api = self._client._get_client(self._service)
method = api.service.SaveBundleList

bundlelist = self.create_bundlelist(data)
if len(data.get('entries', [])) == 0:
raise Exception('No entried found.')

entries = data.get('entries', [])

#
# Add CurrencyRate to entries
#
try:
rate_res = self._client.client.get_currency_list()
if rate_res['count'] >= 1:
rates = dict([(x['Symbol'], x['Rate']) for x in rate_res['results']])
for entry in entries:
entry['currency_rate'] = rates.get(entry['currency_id'], None) or None

except Exception as ex:
print('ERROR getting currency_rate: %s' % ex)

#
# BUNDLE LIST
#
bundlelist = api.factory.create('BundleList')

bundlelist.Bundles = api.factory.create('ArrayOfBundle')

# Allow difference in credit/debit balance.
# This is only applicable when saving journal data (see SaveOption) below.
# Default value is false.
bundlelist.AllowDifference = data.get('allow_difference', True)

# DirectLedger
# If set to false use customer ledger. If set to true use account that is set directly.
bundlelist.DirectLedger = data.get('direct_ledger', False)

# SaveOption
# Can be either 1 or 0.
# Setting 1 saves the bundle as a journal which can then be reviewed and edited on the 24SevenOffice web site.
# Setting 0 saves the bundle directly to the ledger.
bundlelist.SaveOption = data.get('save_option', 1)

# add this single bundle to bundlelist

transaction_numbers = {}
# and add each bundle to bundlelist
for bundle in bundles:
bundlelist.Bundles.Bundle.append(bundle)

return bundlelist

def save_bundle_list(self, bundlelist):
last_transaction_number_by_stamp_number = {}
stamp_numbers_for_transaction_number = {}

for bundle in bundlelist.Bundles.Bundle:
for voucher in bundle.Vouchers.Voucher:
for entry in voucher.Entries.Entry:
if entry.StampNo:
transaction_numbers[entry.StampNo] = voucher.TransactionNo

stamp_numbers = list(transaction_numbers.keys())
last_transaction_number_by_stamp_number[entry.StampNo] = voucher.TransactionNo
stamp_numbers_for_transaction_number = self.append_to_list_for_key(stamp_numbers_for_transaction_number, voucher.TransactionNo, entry.StampNo)

stamp_numbers = list(last_transaction_number_by_stamp_number.keys())
cache_stamp = stamp_numbers[0] if len(stamp_numbers) else None

response = self.do_save_bundle_list(bundlelist, stamp_numbers_for_transaction_number, last_transaction_number_by_stamp_number, stamp_numbers, cache_stamp)

return response

def do_save_bundle_list(self, bundlelist, stamp_numbers_for_transaction_number, last_transaction_number_by_stamp_number, stamp_numbers, cache_stamp):
api = self._client._get_client(self._service)
method = api.service.SaveBundleList

response = self._client._get(method, bundlelist)
response['transaction_ids'] = transaction_numbers

# Include extra data
response['transaction_ids'] = last_transaction_number_by_stamp_number
response['stamp_numbers'] = stamp_numbers
# response['bundlelist'] = bundlelist
response['stamp_numbers_for_transaction_number'] = stamp_numbers_for_transaction_number
response['stamp_no'] = cache_stamp

return response

def append_to_list_for_key(self, dictionary, key, new_value):
values = dictionary.get(key, [])
values.append(new_value)
dictionary[key] = list(set(values))

return dictionary