How to optimize invoice validation - python

I'm working on database that uses lot of data. One invoice could have 7482 different articles. Validating invoice cost so much time, it took 26 minutes to validate one with 7482 articles. I find the method that take time to finish, it is the "action_move_create" inside "odoo\addons\account\models\account_invoice.py".
#api.multi
def action_move_create(self):
""" Creates invoice related analytics and financial move lines """
account_move = self.env['account.move']
for inv in self:
if not inv.journal_id.sequence_id:
raise UserError(_('Please define sequence on the journal related to this invoice.'))
if not inv.invoice_line_ids.filtered(lambda line: line.account_id):
raise UserError(_('Please add at least one invoice line.'))
if inv.move_id:
continue
if not inv.date_invoice:
inv.write({'date_invoice': fields.Date.context_today(self)})
if not inv.date_due:
inv.write({'date_due': inv.date_invoice})
company_currency = inv.company_id.currency_id
# create move lines (one per invoice line + eventual taxes and analytic lines)
iml = inv.invoice_line_move_line_get()
iml += inv.tax_line_move_line_get()
diff_currency = inv.currency_id != company_currency
# create one move line for the total and possibly adjust the other lines amount
total, total_currency, iml = inv.compute_invoice_totals(company_currency, iml)
name = inv.name or ''
if inv.payment_term_id:
totlines = inv.payment_term_id.with_context(currency_id=company_currency.id).compute(total, inv.date_invoice)[0]
res_amount_currency = total_currency
for i, t in enumerate(totlines):
if inv.currency_id != company_currency:
amount_currency = company_currency._convert(t[1], inv.currency_id, inv.company_id, inv._get_currency_rate_date() or fields.Date.today())
else:
amount_currency = False
# last line: add the diff
res_amount_currency -= amount_currency or 0
if i + 1 == len(totlines):
amount_currency += res_amount_currency
iml.append({
'type': 'dest',
'name': name,
'price': t[1],
'account_id': inv.account_id.id,
'date_maturity': t[0],
'amount_currency': diff_currency and amount_currency,
'currency_id': diff_currency and inv.currency_id.id,
'invoice_id': inv.id
})
else:
iml.append({
'type': 'dest',
'name': name,
'price': total,
'account_id': inv.account_id.id,
'date_maturity': inv.date_due,
'amount_currency': diff_currency and total_currency,
'currency_id': diff_currency and inv.currency_id.id,
'invoice_id': inv.id
})
part = self.env['res.partner']._find_accounting_partner(inv.partner_id)
line = [(0, 0, self.line_get_convert(l, part.id)) for l in iml]
line = inv.group_lines(iml, line)
line = inv.finalize_invoice_move_lines(line)
date = inv.date or inv.date_invoice
move_vals = {
'ref': inv.reference,
'line_ids': line,
'journal_id': inv.journal_id.id,
'date': date,
'narration': inv.comment,
}
move = account_move.create(move_vals)
# Pass invoice in method post: used if you want to get the same
# account move reference when creating the same invoice after a cancelled one:
move.post(invoice = inv)
# make the invoice point to that move
vals = {
'move_id': move.id,
'date': date,
'move_name': move.name,
}
inv.write(vals)
return True
Could you suggest some solutions?
We suppose that the hardware is efficient to run odoo correctly.

I optimize it by using raw sql query. I made these codes in account.invoice model:
The first one is the definition of _mock_create_move_line (called in action_move_create).
def _mock_create_move_line(self, model, values, move):
bad_names = ["analytic_line_ids", "tax_ids", "analytic_tag_ids"]
other_fields = [
"currency_id", "debit", "credit", "balance",
"debit_cash_basis", "credit_cash_basis", "balance_cash_basis",
"company_currency_id", "amount_residual",
"amount_residual_currency", "tax_base_amount", "reconciled",
"company_id", "counterpart"
]
cr = self.env.cr
quote = '"{}"'.format
columns = []
columns1 = []
for i, v in enumerate(values):
v = model._add_missing_default_values(v)
account_id = self.env['account.account'].browse(v['account_id'])
# compulsory columns and some stored related columns
# related fields are not triggered, krrrrr
v.update({
'move_id': move.id,
'date_maturity': move.date,
'company_id': account_id.company_id.id,
'date': move.date,
'journal_id': move.journal_id.id,
'user_type_id': account_id.user_type_id.id,
'create_uid': self.env.uid,
'create_date': fields.Datetime.now()
})
######
temp_column = []
for name, val in sorted(v.items()):
if name in bad_names:
continue
field = model._fields[name]
if field.column_type:
col_val = field.convert_to_column(val, model, v)
temp_column.append(col_val)
if not i:
columns1.append((name, field.column_format, col_val))
columns.append(tuple(temp_column))
model.check_access_rule('create')
try:
query = "INSERT INTO {} ({}) VALUES {} RETURNING id".format(
quote(model._table),
", ".join(quote(name) for name, fmt, val in columns1),
", ".join('%s' for fmt in columns),
)
cr.execute(query, columns)
ids = cr.fetchall()
# clear the model cache to take account of the new insertion
# if not executed, relationnal field will not be updated
model.invalidate_cache()
account_move_line_ids = model.browse(ids)
account_move_line_ids.modified(other_fields)
account_move_line_ids.recompute()
# update parent_path
account_move_line_ids._parent_store_create()
except Exception as e:
_logger.info(e)
cr.rollback()
return
The second one is the overriding of native method action_move_create. I make some modification, call _mock_create_move_line if there is 'raw_sql' in the context.
#api.multi
def action_move_create(self):
""" Creates invoice related analytics and financial move lines """
# TODO : make choice between ORM or raw sql according to the context
account_move = self.env['account.move']
for inv in self:
if not inv.journal_id.sequence_id:
raise UserError(_('Please define sequence on the journal related to this invoice.'))
if not inv.invoice_line_ids.filtered(lambda line: line.account_id):
raise UserError(_('Please add at least one invoice line.'))
if inv.move_id:
continue
if not inv.date_invoice:
inv.write({'date_invoice': fields.Date.context_today(self)})
if not inv.date_due:
inv.write({'date_due': inv.date_invoice})
company_currency = inv.company_id.currency_id
# create move lines (one per invoice line + eventual taxes and analytic lines)
iml = inv.invoice_line_move_line_get()
iml += inv.tax_line_move_line_get()
diff_currency = inv.currency_id != company_currency
# create one move line for the total and possibly adjust the other lines amount
total, total_currency, iml = inv.compute_invoice_totals(company_currency, iml)
name = inv.name or ''
if inv.payment_term_id:
totlines = \
inv.payment_term_id.with_context(currency_id=company_currency.id).compute(total, inv.date_invoice)[0]
res_amount_currency = total_currency
for i, t in enumerate(totlines):
if inv.currency_id != company_currency:
amount_currency = company_currency._convert(t[1], inv.currency_id, inv.company_id,
inv._get_currency_rate_date() or fields.Date.today())
else:
amount_currency = False
# last line: add the diff
res_amount_currency -= amount_currency or 0
if i + 1 == len(totlines):
amount_currency += res_amount_currency
iml.append({
'type': 'dest',
'name': name,
'price': t[1],
'account_id': inv.account_id.id,
'date_maturity': t[0],
'amount_currency': diff_currency and amount_currency,
'currency_id': diff_currency and inv.currency_id.id,
'invoice_id': inv.id
})
else:
iml.append({
'type': 'dest',
'name': name,
'price': total,
'account_id': inv.account_id.id,
'date_maturity': inv.date_due,
'amount_currency': diff_currency and total_currency,
'currency_id': diff_currency and inv.currency_id.id,
'invoice_id': inv.id
})
part = self.env['res.partner']._find_accounting_partner(inv.partner_id)
line = [(0, 0, self.line_get_convert(l, part.id)) for l in iml]
line = inv.group_lines(iml, line)
line = inv.finalize_invoice_move_lines(line)
date = inv.date or inv.date_invoice
if self.env.context.get('raw_sql', None):
move_vals = {
'ref': inv.reference,
'journal_id': inv.journal_id.id,
'date': date,
'narration': inv.comment,
}
# remove (0, 0, ...)
# override the group_lines method to avoid looping on next instruction
new_lines = [nl[2] for nl in line]
# TODO do not call compute here, add with ...norecompute()
move = account_move.create(move_vals)
move.env.cr.commit()
self._mock_create_move_line(self.env['account.move.line'], new_lines, move)
# Pass invoice in method post: used if you want to get the same
# account move reference when creating the same invoice after a cancelled one:
# compute move, it is not triggered automatically bc raw sql insertion
# is it correct to call it like this ? find better way
move._amount_compute()
move._compute_partner_id()
move._compute_matched_percentage()
else:
# make default behavior
move_vals = {
'ref': inv.reference,
'line_ids': line,
'journal_id': inv.journal_id.id,
'date': date,
'narration': inv.comment,
}
move = account_move.create(move_vals)
move.post(invoice=inv)
# make the invoice point to that move
vals = {
'move_id': move.id,
'date': date,
'move_name': move.name,
}
inv.write(vals)
return True
Now, the execution time is less than 1 minutes for about 7000 records to insert inside invoice.move.line

Related

for loop only takes last value in python aws dynamodb

I am trying to insert records into a table, but only last record(result data) from the loop is inserting into the table
Here is the code i tried:
CDates = ['2020-05-10','2020-05-12','2020-05-13','2020-05-16','2020-05-20']
ResultData = {}
for date in CDates:
filterDate = Key('Date').eq(id)
appResponse = appTable.scan(FilterExpression = filterDate)
accResp = table.query(KeyConditionExpression = Key('PrimaryId').eq('Key'),FilterExpression = Key('Date').eq(date))
if len(accResp['Items']) == 0:
ResultData['PrimaryId'] = 'Key'
ResultData['CreatedDate'] = date
ResultData['Type'] = 'Appt'
ResultData['Id'] = str(uuid.uuid4())
print(ResultData)
table.put_item(Item=ResultData)
Not getting where did I go wrong
You assigned ResultData outside of the loop and changed the values for the same keys every time the loop ran. Try this:
CDates = ['2020-05-10', '2020-05-12', '2020-05-13', '2020-05-16', '2020-05-20']
for date in CDates:
filterDate = Key('Date').eq(id)
appResponse = appTable.scan(FilterExpression=filterDate)
accResp = table.query(
KeyConditionExpression=Key('PrimaryId').eq('Key'),
FilterExpression=Key('Date').eq(date))
if len(accResp['Items']) == 0:
ResultData = {
'PrimaryId': 'Key',
'CreationDate': date,
'Type': 'Appt',
'Id': str(uuid.uuid4())
}
print(ResultData)
table.put_item(Item=ResultData)

Expected singleton error occurs when return more than one record in odoo?

This method to get the product price from the PO, and it works well if the PO have only one record otherwise I am getting this error.
raise ValueError("Expected singleton: %s" % self)
This is the method
#api.multi
def create_refund_invoice(self):
inv_obj = self.env['account.invoice']
for pick in self.filtered(lambda x:x.return_type):
type = 'in_refund' if pick.return_type == 'purchase' else 'out_refund'
inv_lines = {'type':type, 'partner_id':pick.partner_id.id, 'invoice_line_ids':[]}
account = pick.return_type == 'sale' and pick.partner_id.property_account_receivable_id.id or pick.partner_id.property_account_payable_id.id
inv_lines['account_id'] = account
inv_lines['origin'] = pick.name
inv_lines['name'] = pick.origin
for line in pick.move_lines:
name = line.product_id.partner_ref
for rec in self:
rec.order_id = line.env['purchase.order'].search([('name', '=', line.origin)]).order_line
rec.price = rec.order_id.price_unit
inv_lines['invoice_line_ids'] += [(0, None, {
'product_id':line.product_id.id,
'name':name,
'quantity':line.quantity_done,
'price_unit': rec.price,
'account_id':line.product_id.product_tmpl_id.get_product_accounts()['income'].id})]
if inv_lines['invoice_line_ids']:
inv_id = inv_obj.create(inv_lines)
pick.invoice_id = inv_id.id
It is necessary for odoo that when you are getting more than one record then you can not access it's field values directly.
In your code you are trying to get purchase_order_line of purchase_order It may possible that many lines are available in a single order.
def create_refund_invoice(self):
purchase_order_obj = self.env['purchase.order']
inv_obj = self.env['account.invoice']
for pick in self.filtered(lambda x:x.return_type):
type = 'in_refund' if pick.return_type == 'purchase' else 'out_refund'
inv_lines = {'type':type, 'partner_id':pick.partner_id.id, 'invoice_line_ids':[]}
account = pick.return_type == 'sale' and pick.partner_id.property_account_receivable_id.id or pick.partner_id.property_account_payable_id.id
inv_lines['account_id'] = account
inv_lines['origin'] = pick.name
inv_lines['name'] = pick.origin
for line in pick.move_lines:
name = line.product_id.partner_ref
for rec in self:
order_lines = purchase_order_obj.search([('name', '=', line.origin)]).order_line
for pol in order_lines:
price = pol.order_id.price_unit
inv_lines['invoice_line_ids'] += [(0, None, {
'product_id':line.product_id.id,
'name':name,
'quantity':line.quantity_done,
'price_unit': price,
'account_id':line.product_id.product_tmpl_id.get_product_accounts()['income'].id})
]
if inv_lines['invoice_line_ids']:
inv_id = inv_obj.create(inv_lines)
pick.invoice_id = inv_id.id
I have updated code test above code and update it as per your requirement.

Unable to break infinite loop

There are various posts related to infinite loops on here but none reflect my particular predicament (they deal with Java or they do not match my code format etc). The code I have used is actually source code or 'answer code' to an exercise aimed at new students such as myself and it only supplies the 'correct code without correct format' which for an independent student can complicate things but also provide a more productive challenge.
The code makes solid use of 'functions' and 'calling functions from within other functions' which leaves very little 'global code' as a result, this may make things slightly more complicated but hopefully experienced programmers won't be phased by this.
I think the loop is either an issue with my 'while loop code indentation' or the 'while loop condition/counter code itself'. The loop code takes and uses data from other parts of the program code and shouldn't be completely ruled out but realistically I suspect the problem is one of the two former possible issues of either indentation or internal loop code itself, I have already tried multiple variations of 'indentation layout' as well as making quick fixes (misstyped syntax etc).
The code in question can be found towards the end of the program code (there is only one 'while loop' in the program code) it is in the 'menu options' section of code under '# Loop through quotes selecting those referencing the appropriate month and store the data in the summary dictionary'.
I have included two separate code windows, one highlighting the suspected 'problem code' and the the other with 'full program code'. Any help in any aspect will be appreciated.
Code segment most likely to hold error
def monthlyReport():
file = open(QUOTES_TO_DATE_FILE, 'r')
text = file.read()
file.close()
quotes = text.split()
month = input('Enter month: ')
summary = {'Lawn':{'Quantity' : 0.0, 'Value' : 0.0}, 'Patio' :{'Quantity' : 0.0, 'Value' : 0.0}, 'Water Feature' :{'Quantity' : 0.0, 'Value' : 0.0}}
# Loop through quotes selecting those referencing the appropriate month and
#store the data in summary dictionary
index = 0
while True:
if quotes[index] == month:
inputQuotesFromFile2(quotes[index+1])
summary['Lawn']['Quantity'] = summary['Lawn']['Quantity'] + quote['Lawn']['Width'] * quote['Lawn']['Length']
summary['Lawn']['Value'] = summary['Lawn']['Value'] + quote ['Lawn']['Cost']
summary['Patio']['Quantity'] = summary['Patio']['Quantity'] + quote['Patio']['Width'] * quote['Patio']['Length']
summary['Patio']['Value'] = summary['Patio']['Value'] + quote['Patio']['Cost']
summary['Water Feature']['Quantity'] = summary['Water Feature']['Quantity'] + quote['Water Feature']['Quantity']
summary['Water Feature']['Value'] = summary['Water Feature']['Value'] + quote['Water Feature']['Cost']
index = index + 2
if (index >= len(quotes)):
break
totalValue = summary['Lawn']['Value'] + summary['Patio']['Value'] + summary['Water Feature']['Value']
outputSummaryDictionary(summary, month, totalValue)
Full program code
# `Dictionary containing time values (mins) per square metre/ per feature
##lawn:20 patio:20 water feature:60
TIME = {'Lawn': 20, 'Patio': 20, 'Water Feature': 60}
# Constant for labour cost
##16.49
LABOUR_COST = 16.49
# Variable for filename of list of quotes made to date
##quotesToDateFile
QUOTES_TO_DATE_FILE = 'quotesToDateFile.txt'
# 'Global variables'
# A dictionary that stores quote data temporarily, contains sub dicts for each
#material type including keys for length, width, cost, time/quantity,cost, time
quote = {'Lawn':{'Length': 0 , 'Width': 0 , 'Cost': 0.0 , 'Time': 0.0},
'Patio':{'Length': 0 , 'Width': 0, 'Cost': 0.0 , 'Time': 0.0 },
'Water Feature':{'Quantity': 0 , 'Cost': 0.0 , 'Time': 0.0}}
# A dictionary storing material costs of individual items (can be updated)
materialCost = {'Lawn': 15.5, 'Patio': 20.99, 'Water Feature': 150}
# 'Input'
# Function to input material info defined by a length
##create function with named parameter for 'item'
def inputItemDimensions(item):
s = 'Enter length of ' + item + ':'
length = int(input('Enter length of material: '))
s = 'Enter width of ' + item + ':'
width = int(input('Enter width of material: '))
return length, width
# Function to input material info defined by quantity
##create function with named parameter 'item
def inputItemQuantity(item):
s = 'Enter quantity of ' + item + ':'
quantity = int(input('Enter quantity of items: '))
return quantity
# Function for input of area and quantity
def itemInput():
global quote
quote['Lawn']['Length'], quote['Lawn']['Width'] = inputItemDimensions('lawn')
quote['Patio']['Length'], quote['Patio']['Width'] = inputItemDimensions('concrete patio')
quote['Water Feature']['Quantity'] = inputItemQuantity('water feature')
# 'Cost calculation'
# Function to calculate, output to screen, return the material cost and time
#to install a landscape item installed by length and width
def costCalculation1(num, item, length, width, cost, time):
print('[{0}]'.format(num))
print('Length and width of the {0} = {1} x {2}m'.format(item, length, width))
area = length * width
print('Total area of {0} = {1:.2f}m^2'.format(item, area))
print('Cost of {0} per m^2 = £{1:.2f}'.format(item, cost))
totalCost = area * cost
print('Total cost of {0} = £{1}\n'.format(item, totalCost))
totalTime = area * time
return totalCost, totalTime
# Function to calculate, output to screen and return the material cost and time
#to install a landscape item installed by quantity
def costCalculation2(num, item, quantity, cost, time):
print('[{0}]'.format(num))
print('Quantity of {0} = {1} items'.format(item, quantity))
print('Cost of one {0} = £{1:.2f}'.format(item, cost))
totalCost = quantity * cost
print("Total cost of {0} {1} = £{2}\n".format(quantity, item, totalCost))
totalTime = quantity * time
return totalCost, totalTime
# Function to calculate individual costs of items
def calculateItemCosts():
global quote
quote['Lawn']['Cost'], quote['Lawn']['Time'] = costCalculation1('1', 'lawn', quote['Lawn']['Length'], quote['Lawn']['Width'], materialCost['Lawn'], TIME['Lawn'])
quote['Patio']['Cost'], quote['Patio']['Time'] = costCalculation1('2', 'patio', quote['Patio']['Length'], quote['Patio']['Width'], materialCost['Patio'], TIME['Patio'])
quote['Water Feature']['Cost'], quote['Water Feature']['Time'] = costCalculation2('3', 'water features', quote['Water Feature']['Quantity'], materialCost['Water Feature'], TIME['Water Feature'])
# Function to calculate workimg costs and output them
def workingCost():
print('Working costs:')
totalTime = (quote['Lawn']['Time'] + quote['Patio']['Time'] + quote['Water Feature']['Time']) / 60
labourCost = totalTime * LABOUR_COST
print('Total time to complete work = {0} mins'.format(totalTime))
print('Cost of work per hour = £{0}'.format(LABOUR_COST))
print('Total cost of work = £{0}\n'.format(labourCost))
# Calculate total fee payable by customer, output to screen and file
materialCost = quote['Lawn']['Cost'] + quote['Patio']['Cost'] + quote['Water Feature']['Cost']
totalCost = materialCost + labourCost
print('Total cost to pay = £{0}\n'.format(totalCost))
# 'Output functions'
# Output details concerning item
def outputItems():
outputItems1('1', 'Lawn', quote['Lawn'])
outputItems1('2', 'Patio', quote['Patio'])
outputItems2('3', 'Water Feature', quote['Water Feature'])
# Output dimensions and cost for certain item
def outputItems1(num, item, itemDict):
print('[{0}]'.format(num))
print('Length of width of {0} = {1}m x {2}m'.format(item, itemDict['Length'], itemDict['Width']))
print('Total cost of {0} = £{1}'.format(item, itemDict['Cost']))
print('Time to install {0} = {1}mins\n'.format(item, itemDict['Time'] / 60))
# Output quantity and cost for item
def outputItems2(num, item, itemDict):
print('[{0}]'.format(num))
print('Quantity of {0} = {1} items'.format(item, itemDict['Quantity']))
print('Cost of one {0} = £{1:.2f}'.format(item, itemDict['Cost']))
print('Time to install {0} = {1:.2f} hours\n'.format(item, itemDict['Time'] / 60))
# Output material cost dictionary
def outputMaterialCostDictionary():
for key, value in materialCost.items():
print('{0} = {1}'.format(key, value))
print('\n')
# Output summary dictionary
def outputSummaryDictionary(summaryD, month, totalV):
outputSummaryItem1(['Month', month, '', '', ''])
outputSummaryItem1(['Total', '', 'Total', 'Total', 'Total'])
outputSummaryItem1(['Working', 'Item', 'Square metre', 'Number', 'Monthly'])
outputSummaryItem1(['Costs', '', 'Purchased', 'Purchased', 'Value'])
outputSummaryItem2('Lawn', summaryD['Lawn'])
outputSummaryItem2('Patio', summaryD['Patio'])
outputSummaryItem3('Water Feature', summaryD['Water Feature'])
outputSummaryItem4(totalV)
# Output summary dictionary item ver 1
def outputSummaryItem1(sList):
print('|{0:^13}|{1:^13}|{2:^13}|{3:^13}|{4:^13}|'.format(sList[0], sList[1], sList[2], sList[3], sList[4]))
# Output summary dictionary item ver 2
def outputSummaryItem2(name, item):
print('|{0:^13}|{1:^13}|{2:13.2f}|{3:^13}|{4:13.2f}|'.format('', name, item['Quantity'], '', item['Value']))
# Output summary dictionary item ver 3
def outputSummaryItem3(name, item):
print('|{0:^13}|{1:^13}|{2:^13}|{3:13.0f}|{4:13.2f}|'.format('', name, '', item['Quantity'], item['Value']))
# Output summary dictionary item ver 4
def outputSummaryItem4(totalValue):
print('|{0:^13}|{1:^13}|{2:^13}|{3:^13}|{4:13.2f}|'.format('Total', '', '', '', totalValue))
# 'File handling'
# Function to output file
def outputToFile():
filename = input('Enter file name: ')
file = open(filename, 'w')
month = input('Enter month:' )
print('Filename = {0}....Month = {1}\n'.format(filename, month))
file.write('{0}\n'.format(month))
s = '{0} {1} {2} {3}\n'.format(quote['Lawn']['Length'], quote['Lawn']['Width'], quote['Lawn']['Cost'], quote['Lawn']['Time'])
file.write(s)
s = '{0} {1} {2} {3}\n'.format(quote['Patio']['Length'], quote['Patio']['Width'], quote['Patio']['Cost'], quote['Patio']['Time'])
file.write(s)
s = '{0} {1} {2}\n'.format(quote['Water Feature']['Quantity'], quote['Water Feature']['Cost'], quote['Water Feature']['Time'])
file.write(s)
file.close()
# Update quotes to date file
file = open(QUOTES_TO_DATE_FILE, 'a')
s = '{0} {1}\n'.format(month, filename)
file.write(s)
file.close()
# Function to input quote from file where file name is not known
def inputQuoteFromFile1():
filename = input('Enter name for input file: ')
inputQuoteFromFile2(filename)
# Function to input quote from file when file IS known
def inputQuoteFromFile2(filename):
file = open(filename, 'r')
text = file.read()
list1 = text.split()
file.close()
# Process the data (ignore first item which is the month)
##declare 'quote' dict as global (this might mean this code is within function)
global quote
subDictionary = {'Length' : float(list1[1]), 'Width' : float(list1[2]), 'Cost' : float(list1[3]), 'Time' : float(list1[4])}
quote['Lawn'] = subDictionary
subDictionary = {'Length' : float(list1[5]), 'Width' : float(list1[6]), 'Cost' : float(list1[7]), 'Time' : float(list1[8])}
quote['Patio'] = subDictionary
subDictionary = {'Quantity' : float(list1[9]), 'Cost' : float(list1[10]), 'Time' : float(list1[11])}
quote['Water Feature'] = subDictionary
file.close()
# 'Menu options'
# Function to allow preperation of a new quote
def prepareANewQuote():
itemInput()
calculateItemCosts()
workingCost()
outputToFile()
# Function to load new material costs
def loadNewMaterialCosts():
filename = input('Enter filename: ')
file = open(filename, 'r')
text = file.read()
file.close()
newMaterialCosts = text.split()
# Assign costs to material cost dictionary
index = 0
for key in materialCost.keys():
materialCost['Key'] = float(newMaterialCosts['index'])
index = index + 1
# Output new material costs # NOTE MAY NEED TO BE INDENTED FURTHER
outputMaterialCostDictionary()
# Function to view and load existing quote
def viewExistingQuote():
inputQuoteFromFile1()
outputItems()
workingCost()
# Function to generate monthly report summary
def monthlyReport():
file = open(QUOTES_TO_DATE_FILE, 'r')
text = file.read()
file.close()
quotes = text.split()
month = input('Enter month: ')
summary = {'Lawn':{'Quantity' : 0.0, 'Value' : 0.0}, 'Patio' :{'Quantity' : 0.0, 'Value' : 0.0}, 'Water Feature' :{'Quantity' : 0.0, 'Value' : 0.0}}
# Loop through quotes selecting those referencing the appropriate month and
#store the data in summary dictionary
index = 0
while True:
if quotes[index] == month:
inputQuotesFromFile2(quotes[index+1])
summary['Lawn']['Quantity'] = summary['Lawn']['Quantity'] + quote['Lawn']['Width'] * quote['Lawn']['Length']
summary['Lawn']['Value'] = summary['Lawn']['Value'] + quote ['Lawn']['Cost']
summary['Patio']['Quantity'] = summary['Patio']['Quantity'] + quote['Patio']['Width'] * quote['Patio']['Length']
summary['Patio']['Value'] = summary['Patio']['Value'] + quote['Patio']['Cost']
summary['Water Feature']['Quantity'] = summary['Water Feature']['Quantity'] + quote['Water Feature']['Quantity']
summary['Water Feature']['Value'] = summary['Water Feature']['Value'] + quote['Water Feature']['Cost']
index = index + 2
if (index >= len(quotes)):
break
totalValue = summary['Lawn']['Value'] + summary['Patio']['Value'] + summary['Water Feature']['Value']
outputSummaryDictionary(summary, month, totalValue)
# 'Main' (initialisation)
# Top level function
def start():
while True :
print('Select one of following options')
print('(1) Prepare new quote')
print('(2) Load new cost data')
print('(3) Load and view existing quote')
print('(4) Generate monthly report summary')
print('(5) Exit')
selection = int(input())
if selection == 1:
prepareANewQuote()
elif selection == 2:
loadNewMaterialCosts()
elif selection == 3:
viewExistingQuote()
elif selection == 4:
monthlyReport()
elif selection == 5:
quit()
else:
print('Error unrecognised command')
# Start
start()
index never gets modified if quotes[index] does not equal month, so the code will keep checking the same value over and over again and never proceed.
You should unindent that assignment of index by one level. But really this is not an appropriate use of a while loop; you should use for to iterate over quotes:
for quote in quotes:
(Also note there are two while loops in this code; and actually far too much use of global.)

get total attendance from Timesheet

in ower society, employee's payslip is based on timesheet attendance. so in order to make that possible, I have been changing in openerp(7) code, exactly in payroll.py
the previews code is based on" contract.working_hours " it takes the total of hours and it puts it in pyaslip.number_of_hours
def get_worked_day_lines(self, cr, uid, contract_ids, date_from, date_to, context=None):
"""
#param contract_ids: list of contract id
#return: returns a list of dict containing the input that should be applied for the given contract between date_from and date_to
"""
def was_on_leave(employee_id, datetime_day, context=None):
res = False
day = datetime_day.strftime("%Y-%m-%d")
holiday_ids = self.pool.get('hr.holidays').search(cr, uid, [('state','=','validate'),('employee_id','=',employee_id),('type','=','remove'),('date_from','<=',day),('date_to','>=',day)])
if holiday_ids:
res = self.pool.get('hr.holidays').browse(cr, uid, holiday_ids, context=context)[0].holiday_status_id.name
return res
res = []
for contract in self.pool.get('hr.contract').browse(cr, uid, contract_ids, context=context):
if not contract.working_hours:
#fill only if the contract as a working schedule linked
continue
attendances = {
'name': _("Normal Working Days paid at 100%"),
'sequence': 1,
'code': 'WORK100',
'number_of_days': 0.0,
'number_of_hours': 0.0,
'contract_id': contract.id,
}
leaves = {}
day_from = datetime.strptime(date_from,"%Y-%m-%d")
day_to = datetime.strptime(date_to,"%Y-%m-%d")
nb_of_days = (day_to - day_from).days + 1
for day in range(0, nb_of_days):
working_hours_on_day = self.pool.get('resource.calendar').working_hours_on_day(cr, uid, contract.working_hours, day_from + timedelta(days=day), context)
if working_hours_on_day:
#the employee had to work
leave_type = was_on_leave(contract.employee_id.id, day_from + timedelta(days=day), context=context)
if leave_type:
#if he was on leave, fill the leaves dict
if leave_type in leaves:
leaves[leave_type]['number_of_days'] += 1.0
leaves[leave_type]['number_of_hours'] += working_hours_on_day
else:
leaves[leave_type] = {
'name': leave_type,
'sequence': 5,
'code': leave_type,
'number_of_days': 1.0,
'number_of_hours': working_hours_on_day,
'contract_id': contract.id,
}
else:
#add the input vals to tmp (increment if existing)
attendances['number_of_days'] += 1.0
attendances['number_of_hours'] += working_hours_on_day
leaves = [value for key,value in leaves.items()]
res += [attendances] + leaves
return res
I'v been doing researche about how to browse and search a model,and what I want to do is get total from timesheet where hr_timeshet.employee_id = payslip.employee_id
def get_worked_day_lines(self, cr, uid, employee_id, date_from, date_to, context=None):
res = []
for sheet in self.pool.get('hr_timesheet_sheet.sheet').search(cr,uid, [('state','=','confirm'),('employee_id','=',employee_id)]):
if not sheet:
continue
attendances = {
'name': _("Normal Working Days paid at 100%"),
'sequence': 1,
'code': 'WORK100',
'number_of_days': 0.0,
'number_of_hours': 0.0,
#'contract_id': contract.id,
}
leaves = {}
day_from = datetime.strptime(date_from,"%Y-%m-%d")
day_to = datetime.strptime(date_to,"%Y-%m-%d")
nb_of_days = (day_to - day_from).days + 1
for day in range(0, nb_of_days):
if sheet:
attendances['number_of_days'] += 1.0
attendances['code'] = sheet.total_attendance
I really need that, thanks in advance
error:
Invalid value hr.employee(1,) in domain term ('employee_id', '=', hr.employee(1,))
The error is because you are getting the hr.employee object when you actually need only the id.
Try to change:
('employee_id','=',employee_id)]
to
('employee_id','=',employee_id.id)]
sheet is an integer, you must browse first the object and then access to total_attendance.
Try:
if sheet:
sheet_obj=self.pool.get('hr_timesheet_sheet.sheet').browse(cr, uid, sheet, context=context)
attendances['number_of_days'] += 1.0
attendances['code'] = sheet_obj.total_attendance
I hope this helps you.

Issue on MongoDB bulk load with upsert method

I am trying to load the 8m[rows] * 1k[columns] python dataframe into Mongo. For the performance improvement I have planned to use Mongo bulk operation.There will be update also I have to do in the collections on daily basis so that I used the upsert method of bulk operation. Below is the code which I have prepared,
def BulkLoad(self, Dataset):
counter = 0;
empty = '000'
columns = []
records = []
DataDict = {}
for col in Dataset.columns:
columns.append(col)
try:
db = self.getDatabase()
bulk = db.collection.initialize_ordered_bulk_op()
for j in range(len(Dataset)):
records.clear()
DataDict.clear()
DataDict.update(
{'CreatedBy': empty, 'ModifiedBy': empty, 'Value': Score})
for column in columns:
colValue = str(Dataset[column][j])
if (colValue == 'nan'):
colValue = colValue.replace('nan', '')
DataDict.update({column: colValue})
records.append(DataDict)
print("list is ",records)
Id = DataDict['Id']
Number = DataDict['Number']
print(DataDict)
bulk.find(
{'Id': Id, 'Number': Number}).upsert().update(
{
'$set': {'Id': Id, 'Number': Number,'Events':records}
})
counter += 1
if counter % 1000 == 0:
result = bulk.execute()
logging.info(pprint(result))
bulk = db.coll.initialize_ordered_bulk_op()
if counter % 1000 != 0:
result = bulk.execute()
logging.info(pprint(result))
except Exception as e:
logging.exception(e)
except BulkWriteError as bre:
logging.error(pprint(bre.details))
If I am loading the sample rows of 10 into Mongo collections, All the documents are having the same value of 10th row. I knew its because of python dictionary reference problem .
Can you please anyone give me suggestion on that ?
def BulkLoad(self, Dataset):
counter = 0;
empty = '000'
columns = []
records = []
for col in Dataset.columns:
columns.append(col)
try:
db = self.getDatabase()
bulk = db.collection.initialize_ordered_bulk_op()
for j in range(len(Dataset)):
DataDict = {}
DataDict.update(
{'CreatedBy': empty, 'ModifiedBy': empty, 'Value': Score})
for column in columns:
colValue = str(Dataset[column][j])
if (colValue == 'nan'):
colValue = colValue.replace('nan', '')
DataDict.update({column: colValue})
records.append(DataDict)
print("list is ",records)
Id = DataDict['Id']
Number = DataDict['Number']
print(DataDict)
bulk.find(
{'Id': Id, 'Number': Number}).upsert().update(
{
'$set': {'Id': Id, 'Number': Number,'Events':records}
})
counter += 1
if counter % 1000 == 0:
result = bulk.execute()
logging.info(pprint(result))
bulk = db.coll.initialize_ordered_bulk_op()
if counter % 1000 != 0:
result = bulk.execute()
logging.info(pprint(result))
except Exception as e:
logging.exception(e)
except BulkWriteError as bre:
logging.error(pprint(bre.details))

Categories