Multiple creations on Odoo/Openerp res.partner table fail when one by one succeed - odoo

Here is what I am trying to do, I have a CSV file that has some records that I want to import on my installation. The following code works when I put a return None statement on the end of the loop. (Which you will find commented out
Upon the click of a button this method will be executed in order to loop through all the rows on the CSV and depending on the conditions create a new res.partner record.
(this has been implemented via XML-RPC calls and it worked flawlessly.)
The problem is this: When I stop the execution after the import of one CSV row, everything works (the record on res.partner is created), when I leave it running with the loop no records are created on the table res.partner (I get no errors, no exceptions whatsoever. I even get the newly created record's id upon the invocation of res_partner_obj.create() ).
Note: You will find lots of irrelevant code to my problem (which is why the records on res.partner are not created). I just put it there for the sake of completeness)
def gms_import_test(self, cr, uid, vals, context=None, check=True):
start_time = time.time()
res_partner_obj = self.pool.get('res.partner')
sales_teams_obj = self.pool.get('crm.case.section')
res_partner_title_obj = self.pool.get('res.partner.title')
customer_kunden_obj = self.pool.get('customer.kundengruppe')
res_country_obj = self.pool.get('res.country')
account_account_obj = self.pool.get('account.account')
crm_phonecall_obj = self.pool.get('crm.phonecall')
account_account_type_obj = self.pool.get('account.account.type')
# sys.path[0] == module's path + /addons/gmsimport/+ file's name
with open(sys.path[0] + '/addons/gmsimport/' + '21.9.2015.try8.csv') as csv_file: # TODO THESE MUST CHANGE UPON DEPLOYMENT TO DIFFERENT MACHINES
csv_reader = csv.reader(csv_file, delimiter='~', quotechar='^')
# Get the teams
sales_team_direct_sales_ID = sales_teams_obj.search(cr, uid, [('name', '=', 'Direct Sales')])
sales_team_0_ID = sales_teams_obj.search(cr, uid, [('name', '=', '0')])
sales_team_1_ID = sales_teams_obj.search(cr, uid, [('name', '=', '1')])
sales_team_2_ID = sales_teams_obj.search(cr, uid, [('name', '=', '2')])
sales_team_3_ID = sales_teams_obj.search(cr, uid, [('name', '=', '3')])
sales_team_4_ID = sales_teams_obj.search(cr, uid, [('name', '=', '4')])
sales_team_5_ID = sales_teams_obj.search(cr, uid, [('name', '=', '5')])
sales_team_6_ID = sales_teams_obj.search(cr, uid, [('name', '=', '6')])
sales_team_7_ID = sales_teams_obj.search(cr, uid, [('name', '=', '7')])
sales_team_8_ID = sales_teams_obj.search(cr, uid, [('name', '=', '8')])
sales_team_9_ID = sales_teams_obj.search(cr, uid, [('name', '=', '9')])
# Search for the titles, create them if they do not exist
damen_und_herren_title_ID = res_partner_title_obj.search(cr, uid, [('name', '=', 'Sehr geehrte Damen und Herren')])
if not damen_und_herren_title_ID:
damen_und_herren_title_ID = res_partner_title_obj.create(cr, uid, {'name':'Sehr geehrte Damen und Herren'})
if type(damen_und_herren_title_ID) is list:
damen_und_herren_title_ID = damen_und_herren_title_ID[0]
frau_title_ID = res_partner_title_obj.search(cr, uid, [('name', '=', 'Sehr geehrte Frau')])
if not frau_title_ID:
frau_title_ID = res_partner_title_obj.create(cr, uid, {'name':'Sehr geehrte Frau'})
if type(frau_title_ID) is list:
frau_title_ID = frau_title_ID[0]
herr_title_ID = res_partner_title_obj.search(cr, uid, [('name', '=', 'Sehr geehrter Herr')])
if not herr_title_ID:
herr_title_ID = res_partner_title_obj.create(cr, uid, {'name':'Sehr geehrter Herr'})
if type(herr_title_ID) is list:
herr_title_ID = herr_title_ID[0]
account_type_id = account_account_type_obj.search(cr, uid, [('name', '=', 'Receivable')])
# Checking to see whether there exists the "1200 - Forderungen aus Lieferungen und Leistungen account"
forderungen_account = account_account_obj.search(cr, uid, [('code', '=', 1200)])
if type(forderungen_account) is list and len(forderungen_account) > 0:
forderungen_account = forderungen_account[0]
account_payable_ID = account_account_obj.search(cr, uid, [('code', '=', 'Kunden - Diverse1')])
if type(account_payable_ID) is list:
account_payable_ID = account_payable_ID[0]
next(csv_reader, None) # To skip header row.
row_counter = 2
empty_name_counter = 0
for row in csv_reader:
print 'PROCESS IN ROW: ' + str(row_counter)
final_customer_name = None
if len(str(row[15]).strip()) > 0:
# If Firma is not empty, customer's name == Firma + Zusatz
final_customer_name = row[15] + ' ' + row[64]
else:
# If Firma is empty, customer's name == Vorname + Name
final_customer_name = row[63] + ' ' + row[45]
if final_customer_name:
empty_name_counter += 1
logging.info("Customer name is " + str(final_customer_name))
# search for the customer's existance, if exists do not add her
customer_id = res_partner_obj.search(cr, uid, [('name', '=', final_customer_name)])
print 'Searching with customer name ' + final_customer_name
if not customer_id:
# Customer does not exist, only then make the calls
# Fields with relations that must be treated in a special way
# x_kundengruppe, country_id, name
print 'customer.kundengruppe ' + str(row[6])
x_kundengruppe_id = customer_kunden_obj.search(cr, uid, [('name', '=', row[6].decode('utf8'))])
if not x_kundengruppe_id:
# kundergruppe does not exist (create a record on the model customer.kundengruppe and store its id)
print 'Creating kundengruppe'
x_kundengruppe_id = customer_kunden_obj.create(cr, uid, {'name':row[6]})
country_id = []
if str(row[27]).strip():
if str(row[27]) == 'Great Britain':
country_id = res_country_obj.search(cr, uid, [('name', '=', 'United Kingdom')])
else:
country_id = res_country_obj.search(cr, uid, [('name', '=', row[27])])
mittarbeitergrupe = None
if row[16] == '0 bis 4':
mittarbeitergrupe = '0_4'
elif row[16] == '5 bis 9':
mittarbeitergrupe = '5_9'
elif row[16] == '10 bis 19':
mittarbeitergrupe = '10_19'
elif row[16] == '20 bis 34':
mittarbeitergrupe = '20_34'
elif row[16] == '35 bis 49':
mittarbeitergrupe = '35_49'
elif row[16] == '50 bis 99':
mittarbeitergrupe = '50_99'
elif row[16] == 'über 100':
mittarbeitergrupe = 'uber_100'
final_customer_number_list = []
final_customer_number = None
print row[10]
if len(row[10]) < 8:
# Get row[10] length. Subtract it from 8. That's how many zeros must be put. Create a new string with zeros in front and number postfixed
zeros = 8 - len(row[10])
# final_customer_number_list.append('\'')
for y in range(0, zeros):
final_customer_number_list.append(str(0))
final_customer_number_list.append(str(row[10]))
# final_customer_number_list.append('\'')
final_customer_number = ''.join(final_customer_number_list)
print 'Customer\'s number length < 8. Prefixing ' + str(zeros) + ' zeros'
print 'final x_customer_number: ' + str(final_customer_number)
else:
final_customer_number = str(row[10])
# Make the country_id from an array to a single int variable
if len(country_id) > 0:
print 'SETTING COUNTRY ID TO ' + str(country_id)
country_id = country_id[0]
if type(x_kundengruppe_id) is list and len(x_kundengruppe_id) > 0:
x_kundengruppe_id = x_kundengruppe_id[0]
comment_section = self.assemble_internal_log(row)
final_title = self.assemble_customer_title(row, damen_und_herren_title_ID, frau_title_ID, herr_title_ID)
# Check x_mitarbeiter
if len(row[2].strip()) == 0:
row[2] = 0
else:
row[2] = int(row[2])
fields_to_be_inserted = { 'x_kundengruppe':x_kundengruppe_id,
'x_customer_number':final_customer_number, # (customer number cannot be less than 8 digits)
'vat':row[12],
'email':row[14],
'name':final_customer_name,
'x_mittarbeitergruppe':mittarbeitergrupe,
'title':final_title,
'x_a_kunde':row[23],
'website':row[24],
'country_id':country_id,
'mobile':filter(lambda x: x.isdigit(), row[44]),
'city':row[46],
'zip':row[49],
'function':str(row[50]),
'street':row[57] + str(row[21]), # street and House No
'fax':filter(lambda x: x.isdigit(), row[59]),
'phone':filter(lambda x: x.isdigit(), row[60]),
'comment':comment_section,
'x_mitarbeiter':row[2],
'property_account_payable':account_payable_ID,
}
log_entries = []
# column_index_list = [67, 68, 76, 77, 85, 86, 94, 95, 103, 104, 112, 113, 121, 122, 130, 131, 139, 140, 148, 149, 157, 158, 166, 167, 175, 176, 184, 185, 193, 194, 202, 203, 211, 212, 220, 221, 229, 230, 238, 239, 247, 248]
column_index_list = [67, 76, 85, 94, 103, 112, 121, 130, 139, 148, 157, 166, 175, 184, 193, 202, 211, 220, 229, 238, 247]
# search through the CSV to find those fields that contain (log note/date) and put them in internal log
for x in column_index_list:
if len(row[x].strip()) > 0:
print 'Log entry found, adding to the list'
log_entries.append(row[x + 1] + '||||' + row[x])
if customer_id:
# Customer exists, do not add her
print 'Customer ' + final_customer_name + ' exists. We do not add this one.'
logging.info('Customer ' + final_customer_name + ' exists. We do not add this one.')
else:
try:
logging.info('Creating customer ' + str(final_customer_name) + ', ' + str(row[15]))
created_customer_id = res_partner_obj.create(cr, uid, fields_to_be_inserted)
print 'CREATED CUSTOMER: ' + str(final_customer_name) + ' ID: ' + str(created_customer_id)
sales_team_id = None
# If PLZ field is not empty and is a 5 digit number
if row[49] and str(row[49]).isdigit() and len(str(row[49])) == 5:
# Check the first digit and assign to it a Sales Team
if int(str(row[49])[0]) == 1:
sales_team_id = sales_team_1_ID
elif int(str(row[49])[0]) == 2:
sales_team_id = sales_team_2_ID
elif int(str(row[49])[0]) == 3:
sales_team_id = sales_team_3_ID
elif int(str(row[49])[0]) == 4:
sales_team_id = sales_team_4_ID
elif int(str(row[49])[0]) == 5:
sales_team_id = sales_team_5_ID
elif int(str(row[49])[0]) == 6:
sales_team_id = sales_team_6_ID
elif int(str(row[49])[0]) == 7:
sales_team_id = sales_team_7_ID
elif int(str(row[49])[0]) == 8:
sales_team_id = sales_team_8_ID
elif int(str(row[49])[0]) == 9:
sales_team_id = sales_team_9_ID
# If the PLZ field is not empty and is a 4 digit number
elif row[49] and str(row[49]).isdigit() and len(str(row[49])) == 4: # int(row[49]) >= 0 and int(row[49]) <= 9999:
sales_team_id = sales_team_0_ID
# Everything else goes to the Direct Sales team
else:
sales_team_id = sales_team_direct_sales_ID
if len(sales_team_id) > 0:
print 'SECTION ID: ' + str(sales_team_id)
res_partner_obj.write(cr, uid, created_customer_id, {'section_id':str(sales_team_id[0])})
# personal account for each customer
# Check if account exists for certain customer
account_id = account_account_obj.search(cr, uid, [('name', '=', final_customer_name)])
if not account_id:
print 'Creating and linking new account for customer ' + final_customer_name + ' CODE: ' + str(row[10])
# Creating account (parent_id can be empty. If so, do not change the parent_id field; let it be)
account_id = account_account_obj.create(cr, uid, {'code': row[10],
'name': final_customer_name,
'type':'receivable',
'user_type': account_type_id[0],
'parent_id': forderungen_account
})
# In any case assign the account to the customer
if type(account_id) is list:
account_id = account_id[0]
print 'ACCOUNT ID TO LINK' + str(account_id)
res_partner_obj.write(cr, uid, created_customer_id, {'property_account_receivable':account_id})
except Exception, e:
#pass
print '===> ERROR ' + str(e) # If error on account creation, no problem keep going
for log_entry in log_entries:
log = log_entry.split('||||', 2)
crm_phonecall_obj.create(cr, uid, {'date':log[0], 'name':log[1], 'state':'done', 'partner_id':created_customer_id})
if time.time() - start_time > 500:
print '500 secs passed'
return None
row_counter += 1
#return None

Related

Scrapy - issues with 'dont_filter' option for Requests

I must include the option dont_filter=True into each request of my spider, I've already used this option but I don't know why this time I get this error:
Unhandled Error
Traceback (most recent call last):
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\scrapy\commands\crawl.py", line 58, in run
self.crawler_process.start()
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\scrapy\crawler.py", line 293, in start
reactor.run(installSignalHandlers=False) # blocking call
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\twisted\internet\base.py", line 1283, in run
self.mainLoop()
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\twisted\internet\base.py", line 1292, in mainLoop
self.runUntilCurrent()
--- <exception caught here> ---
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\twisted\internet\base.py", line 913, in runUntilCurrent
call.func(*call.args, **call.kw)
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\scrapy\utils\reactor.py", line 41, in __call__
return self._func(*self._a, **self._kw)
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\scrapy\core\engine.py", line 135, in _next_request
self.crawl(request, spider)
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\scrapy\core\engine.py", line 210, in crawl
self.schedule(request, spider)
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\scrapy\core\engine.py", line 216, in schedule
if not self.slot.scheduler.enqueue_request(request):
File "C:\Users\coppe\Anaconda3\envs\scrapyEnv\lib\site-packages\scrapy\core\scheduler.py", line 54, in enqueue_request
if not request.dont_filter and self.df.request_seen(request):
builtins.AttributeError: 'dict' object has no attribute 'dont_filter'
Here is my Spider (sorry it is quite big):
class communes_spider(scrapy.Spider):
name = "corrections"
firstSearchDate = datetime(2019, 8, 4)
crawlDate = firstSearchDate - timedelta(days=31)
path = 'D:/Données/Drivy/'
JSON = []
custom_settings = {
'ROBOTSTXT_OBEY' : True,
'DOWNLOAD_DELAY' : 6,
'CONCURRENT_REQUESTS' : 1,
'CONCURRENT_REQUESTS_PER_DOMAIN': 1,
'AUTOTHROTTLE_ENABLED' : True,
'AUTOTHROTTLE_START_DELAY' : 6,
'LOG_STDOUT' : True,
'LOG_FILE' : 'D:/Données/Drivy/' + str(datetime.date(firstSearchDate)) + '_bis' '/' + 'log_' + str(datetime.date(crawlDate)) + '_' + str(datetime.date(firstSearchDate)) + '.txt',
'FEED_FORMAT': 'json',
'FEED_URI': 'file:///D:/Données/Drivy/' + str(datetime.date(firstSearchDate)) + '_bis' + '/' + str(datetime.date(crawlDate)) + '_' + str(datetime.date(firstSearchDate)) + '.json',
}
start_urls = "https://fr.be.getaround.com/car_models/estimated_earnings?utf8=%E2%9C%93&car_model_estimation%5Bcar_brand_id%5D={}&car_model_estimation%5Bcar_model_id%5D={}&car_model_estimation%5Brelease_year%5D={}&car_model_estimation%5Bmileage%5D={}&car_model_estimation%5Blatitude%5D={}&car_model_estimation%5Blongitude%5D={}&car_model_estimation%5Bregistration_country%5D=BE&car_model_estimation%5Bwith_open_landing_multiplier%5D={}"
def start_requests(self):
with open('C:/Users/coppe/drivy/carBrands.json') as json_file:
brands = json.load(json_file)
with open(self.path + str(datetime.date(self.firstSearchDate)) + '/' + str(datetime.date(self.crawlDate)) + '_' + str(datetime.date(self.firstSearchDate)) + '.json') as json_file:
cars = json.load(json_file)
for car in cars:
if car['carBrand'] == "Citroën":
car['carBrand'] = car['carBrand'].replace('ë','e')
if car['carBrandID'] == 'other' or car['carModelID'] == 'other':
for brand in brands:
if car['carBrand'].lower() == brand['brandName'].lower():
car['carBrandID'] = brand['brandID']
for model in brand['models']:
if car['carModel'].lower() == model['modelNameFrench'].lower() or car['carModel'].lower() == model['modelNameDutch'].lower():
car['carModelID'] = model['modelID']
else:
pass
else:
pass
if car['mileageCode']=='6':
url = self.start_urls.format(car['carBrandID'],car['carModelID'],car['immatricYear'],5,car['carLat'],car['carLong'],car['open'])
else:
url = self.start_urls.format(car['carBrandID'],car['carModelID'],car['immatricYear'],car['mileageCode'],car['carLat'],car['carLong'],car['open'])
yield scrapy.Request(
url=url,
callback=self.parse_sugPrice,
meta={'car':car},
dont_filter=True,
)
elif datetime.date(datetime.strptime(car['crawlDate'],'%Y-%m-%d')).year == 2020:
if car['mileageCode']=='6':
url = self.start_urls.format(car['carBrandID'],car['carModelID'],car['immatricYear'],5,car['carLat'],car['carLong'],car['open'])
else:
url = self.start_urls.format(car['carBrandID'],car['carModelID'],car['immatricYear'],car['mileageCode'],car['carLat'],car['carLong'],car['open'])
yield scrapy.Request(
url=url,
callback=self.parse_sugPrice,
meta={'car':car},
dont_filter=True,
)
else:
yield car
def parse_sugPrice(self, response):
data = json.loads(response.text, encoding="utf8")
selector = Selector(data['html'])
eligibleObj = json.loads(selector.css('a::attr(data-estimated-earnings)').get())
openEligible = response.meta['car']['openEligible']
if response.meta['car']['carBrandID'] == 'other' or response.meta['car']['carModelID'] == 'other':
response.meta['car']['suggestedPrice'] = -1 # No estimation available
else:
if response.meta['car']['open'] == False and openEligible == True:
estimEarnings = int(re.sub("\D",'',selector.css('span.car_model_estimation_result_amount::text').get()))
correctedEstimEarnings = estimEarnings/1.25
response.meta['car']['suggestedPrice'] = correctedEstimEarnings/20 # Suggested price based current earnings condition on open decision (open is true or false)
elif response.meta['car']['open'] == True and openEligible == False:
estimEarnings = int(re.sub("\D",'',selector.css('span.car_model_estimation_result_amount::text').get()))
correctedEstimEarnings = estimEarnings*1.25
response.meta['car']['suggestedPrice'] = correctedEstimEarnings/15 # Suggested price based current earnings condition on open decision (open is true or false)
elif response.meta['car']['open'] == True and openEligible == True:
estimEarnings = int(re.sub("\D",'',selector.css('span.car_model_estimation_result_amount::text').get()))
response.meta['car']['suggestedPrice'] = estimEarnings/20 # Suggested price based current earnings condition on open decision (open is true or false)
else:
estimEarnings = int(re.sub("\D",'',selector.css('span.car_model_estimation_result_amount::text').get()))
response.meta['car']['suggestedPrice'] = estimEarnings/15 # Suggested price based current earnings condition on open decision (open is true or false)
if response.meta['car']['numEvalCar'] > 0:
if response.meta['car']['firstReviewYear'] != datetime.now().year:
estimMembership = datetime.now().year - response.meta['car']['firstReviewYear'] # in years
correctedYear = response.meta['car']['immatricYear'] + estimMembership
if response.meta['car']['mileageCode']=='6':
suggestedPriceLink = "https://fr.be.getaround.com/car_models/estimated_earnings?utf8=%E2%9C%93&car_model_estimation%5Bcar_brand_id%5D={}&car_model_estimation%5Bcar_model_id%5D={}&car_model_estimation%5Brelease_year%5D={}&car_model_estimation%5Bmileage%5D={}&car_model_estimation%5Blatitude%5D={}&car_model_estimation%5Blongitude%5D={}&car_model_estimation%5Bregistration_country%5D=BE&car_model_estimation%5Bwith_open_landing_multiplier%5D={}".format(response.meta['car']['carBrandID'],response.meta['car']['carModelID'],correctedYear,'5',response.meta['car']['carLat'],response.meta['car']['carLong'],response.meta['car']['open'])
else:
suggestedPriceLink = "https://fr.be.getaround.com/car_models/estimated_earnings?utf8=%E2%9C%93&car_model_estimation%5Bcar_brand_id%5D={}&car_model_estimation%5Bcar_model_id%5D={}&car_model_estimation%5Brelease_year%5D={}&car_model_estimation%5Bmileage%5D={}&car_model_estimation%5Blatitude%5D={}&car_model_estimation%5Blongitude%5D={}&car_model_estimation%5Bregistration_country%5D=BE&car_model_estimation%5Bwith_open_landing_multiplier%5D={}".format(response.meta['car']['carBrandID'],response.meta['car']['carModelID'],correctedYear,response.meta['car']['mileageCode'],response.meta['car']['carLat'],response.meta['car']['carLong'],response.meta['car']['open'])
yield scrapy.Request(
url=suggestedPriceLink,
callback=self.parse_correctSugPrice,
meta={'car':response.meta['car']},
dont_filter=True,
)
else:
yield response.meta['car']
else:
yield response.meta['car']
def parse_correctSugPrice(self, response):
data = json.loads(response.text, encoding="utf8")
selector = Selector(data['html'])
eligibleObj = json.loads(selector.css('a::attr(data-estimated-earnings)').get())
openEligible = response.meta['car']['openEligible']
if response.meta['car']['carBrandID'] == 'other' or response.meta['car']['carModelID'] == 'other':
response.meta['car']['correctSuggestedPrice'] = -1 # No estimation available
else:
if response.meta['car']['open'] == False and openEligible == True:
estimEarnings = int(re.sub("\D",'',selector.css('span.car_model_estimation_result_amount::text').get()))
correctedEstimEarnings = estimEarnings/1.25
response.meta['car']['correctSuggestedPrice'] = correctedEstimEarnings/20 # Suggested price based corrected earnings condition on open decision (open is true or false) and that this decision was the same at firstReviewYear.
elif response.meta['car']['open'] == True and openEligible == False:
estimEarnings = int(re.sub("\D",'',selector.css('span.car_model_estimation_result_amount::text').get()))
correctedEstimEarnings = estimEarnings*1.25
response.meta['car']['correctSuggestedPrice'] = correctedEstimEarnings/15 # Suggested price based corrected earnings condition on open decision (open is true or false) and that this decision was the same at firstReviewYear.
elif response.meta['car']['open'] == True and openEligible == True:
estimEarnings = int(re.sub("\D",'',selector.css('span.car_model_estimation_result_amount::text').get()))
response.meta['car']['correctSuggestedPrice'] = estimEarnings/20 # Suggested price based corrected earnings condition on open decision (open is true or false) and that this decision was the same at firstReviewYear.
else:
estimEarnings = int(re.sub("\D",'',selector.css('span.car_model_estimation_result_amount::text').get()))
response.meta['car']['correctSuggestedPrice'] = estimEarnings/15 # Suggested price based corrected earnings condition on open decision (open is true or false) and that this decision was the same at firstReviewYear.
yield response.meta['car']
Did I miss something ?
dont_filter=True should be inside scrapy.Request meta dict:
meta = {'dont_filter': True , 'car':...}

Porting addon from Odoo 9 to Odoo 10 - ProgrammingError: can't adapt type 'account.tax'

While trying to reuse this Odoo 9 addon https://www.odoo.com/apps/modules/9.0/purchase_recurring_orders/ | github code to Odoo 10, I am facing the following issue:
File "/usr/lib/python2.7/dist-packages/odoo/custom_addons/purchase_recurring_orders/models/recurring_orders.py", line 310, in generate_initial_order
order = self.create_order(self.start_date, agreement_lines)
...
ProgrammingError: can't adapt type 'account.tax'
Full error can be seen here:
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/odoo/http.py", line 640, in _handle_exception
return super(JsonRequest, self)._handle_exception(exception)
File "/usr/lib/python2.7/dist-packages/odoo/http.py", line 677, in dispatch
result = self._call_function(**self.params)
File "/usr/lib/python2.7/dist-packages/odoo/http.py", line 333, in _call_function
return checked_call(self.db, *args, **kwargs)
File "/usr/lib/python2.7/dist-packages/odoo/service/model.py", line 101, in wrapper
return f(dbname, *args, **kwargs)
File "/usr/lib/python2.7/dist-packages/odoo/http.py", line 326, in checked_call
result = self.endpoint(*a, **kw)
File "/usr/lib/python2.7/dist-packages/odoo/http.py", line 935, in __call__
return self.method(*args, **kw)
File "/usr/lib/python2.7/dist-packages/odoo/http.py", line 506, in response_wrap
response = f(*args, **kw)
File "/usr/lib/python2.7/dist-packages/odoo/addons/web/controllers/main.py", line 889, in call_button
action = self._call_kw(model, method, args, {})
File "/usr/lib/python2.7/dist-packages/odoo/addons/web/controllers/main.py", line 877, in _call_kw
return call_kw(request.env[model], method, args, kwargs)
File "/usr/lib/python2.7/dist-packages/odoo/api.py", line 681, in call_kw
return call_kw_multi(method, model, args, kwargs)
File "/usr/lib/python2.7/dist-packages/odoo/api.py", line 672, in call_kw_multi
result = method(recs, *args, **kwargs)
File "/usr/lib/python2.7/dist-packages/odoo/custom_addons/purchase_recurring_orders/models/recurring_orders.py", line 310, in generate_initial_order
order = self.create_order(self.start_date, agreement_lines)
File "/usr/lib/python2.7/dist-packages/odoo/custom_addons/purchase_recurring_orders/models/recurring_orders.py", line 259, in create_order
order_line_obj.create(order_line_vals)
File "/usr/lib/python2.7/dist-packages/odoo/addons/purchase/models/purchase.py", line 557, in create
line = super(PurchaseOrderLine, self).create(values)
File "/usr/lib/python2.7/dist-packages/odoo/models.py", line 3830, in create
record = self.browse(self._create(old_vals))
File "/usr/lib/python2.7/dist-packages/odoo/models.py", line 3987, in _create
field.write(self.with_context(rel_context), vals[name])
File "/usr/lib/python2.7/dist-packages/odoo/fields.py", line 2402, in write
link(act[2])
File "/usr/lib/python2.7/dist-packages/odoo/fields.py", line 2367, in link
cr.execute(query, (records.ids, list(sub_ids), tuple(records.ids)))
File "/usr/lib/python2.7/dist-packages/odoo/sql_db.py", line 154, in wrapper
return f(self, *args, **kwargs)
File "/usr/lib/python2.7/dist-packages/odoo/sql_db.py", line 231, in execute
res = self._obj.execute(query, params)
•ProgrammingError: can't adapt type 'account.tax'
So far I did not modify anything else than the group use.
This is the code of recurring_orders:
# -*- coding: utf-8 -*-
##############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
# Copyright (C) 2009-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
# Author: Jesni Banu(<http://www.cybrosys.com>)
# you can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# It is forbidden to publish, distribute, sublicense, or sell copies
# of the Software or modified copies of the Software.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from datetime import timedelta
from datetime import datetime
from dateutil.relativedelta import relativedelta
from openerp import models, fields, api, exceptions, _
import openerp.addons.decimal_precision as dp
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
class Agreement(models.Model):
_name = 'purchase.recurring_orders.agreement'
_inherit = ['mail.thread']
_description = "Recurring orders agreement"
#api.model
def __get_next_term_date(self, date, unit, interval):
if unit == 'days':
return date + timedelta(days=interval)
elif unit == 'weeks':
return date + timedelta(weeks=interval)
elif unit == 'months':
return date + relativedelta(months=interval)
elif unit == 'years':
return date + relativedelta(years=interval)
#api.multi
def _compute_next_expiration_date(self):
for agreement in self:
if agreement.prolong == 'fixed':
agreement.next_expiration_date = agreement.end_date
elif agreement.prolong == 'unlimited':
now = fields.Date.from_string(fields.Date.today())
date = self.__get_next_term_date(
fields.Date.from_string(agreement.start_date),
agreement.prolong_unit, agreement.prolong_interval)
while date < now:
date = self.__get_next_term_date(
date, agreement.prolong_unit,
agreement.prolong_interval)
agreement.next_expiration_date = date
else:
agreement.next_expiration_date = self.__get_next_term_date(
fields.Date.from_string(agreement.last_renovation_date or
agreement.start_date),
agreement.prolong_unit, agreement.prolong_interval)
def _default_company_id(self):
company_model = self.env['res.company']
company_id = company_model._company_default_get('purchase')
return company_model.browse(company_id.id)
name = fields.Char(
string='Name', size=100, index=True, required=True,
help='Name that helps to identify the agreement')
number = fields.Char(
string='Agreement number', index=True, size=32, copy=False,
help="Number of agreement. Keep empty to get the number assigned by a "
"sequence.")
active = fields.Boolean(
string='Active', default=True,
help='Unchecking this field, quotas are not generated')
partner_id = fields.Many2one(
comodel_name='res.partner', string='Supplier', index=True,
change_default=True, required=True,
help="Supplier you are making the agreement with")
company_id = fields.Many2one(
comodel_name='res.company', string='Company', required=True,
help="Company that signs the agreement", default=_default_company_id)
start_date = fields.Date(
string='Start date', index=True, copy=False,
help="Beginning of the agreement. Keep empty to use the current date")
prolong = fields.Selection(
selection=[('recurrent', 'Renewable fixed term'),
('unlimited', 'Unlimited term'),
('fixed', 'Fixed term')],
string='Prolongation', default='unlimited',
help="Sets the term of the agreement. 'Renewable fixed term': It sets "
"a fixed term, but with possibility of manual renew; 'Unlimited "
"term': Renew is made automatically; 'Fixed term': The term is "
"fixed and there is no possibility to renew.", required=True)
end_date = fields.Date(
string='End date', help="End date of the agreement")
prolong_interval = fields.Integer(
string='Interval', default=1,
help="Interval in time units to prolong the agreement until new "
"renewable (that is automatic for unlimited term, manual for "
"renewable fixed term).")
prolong_unit = fields.Selection(
selection=[('days', 'days'),
('weeks', 'weeks'),
('months', 'months'),
('years', 'years')],
string='Interval unit', default='years',
help='Time unit for the prolongation interval')
agreement_line = fields.One2many(
comodel_name='purchase.recurring_orders.agreement.line',
inverse_name='agreement_id', string='Agreement lines')
order_line = fields.One2many(
comodel_name='purchase.order', copy=False, inverse_name='agreement_id',
string='Orders', readonly=True)
renewal_line = fields.One2many(
comodel_name='purchase.recurring_orders.agreement.renewal', copy=False,
inverse_name='agreement_id', string='Renewal lines', readonly=True)
last_renovation_date = fields.Date(
string='Last renovation date',
help="Last date when agreement was renewed (same as start date if not "
"renewed)")
next_expiration_date = fields.Date(
compute="_compute_next_expiration_date", string='Next expiration date')
state = fields.Selection(
selection=[('empty', 'Without orders'),
('first', 'First order created'),
('orders', 'With orders')],
string='State', readonly=True, default='empty')
renewal_state = fields.Selection(
selection=[('not_renewed', 'Agreement not renewed'),
('renewed', 'Agreement renewed')],
string='Renewal state', readonly=True, default='not_renewed')
notes = fields.Text('Notes')
_sql_constraints = [
('number_uniq', 'unique(number)', 'Agreement number must be unique !'),
]
#api.constrains('start_date', 'end_date')
def _check_dates(self):
for record in self:
if record.end_date and record.end_date < record.start_date:
raise exceptions.Warning(
_('Agreement end date must be greater than start date'))
#api.model
def create(self, vals):
if not vals.get('start_date'):
vals['start_date'] = fields.Date.today()
if not vals.get('number'):
vals['number'] = self.env['ir.sequence'].get(
'purchase.r_o.agreement.sequence')
return super(Agreement, self).create(vals)
#api.multi
def write(self, vals):
value = super(Agreement, self).write(vals)
if (any(vals.get(x) is not None for x in
['active', 'number', 'agreement_line', 'prolong', 'end_date',
'prolong_interval', 'prolong_unit', 'partner_id'])):
self.unlink_orders(fields.Date.today())
return value
#api.model
def copy(self, id, default=None):
agreement_record = self.browse(id)
default.update({
'state': 'empty',
'active': True,
'name': '%s*' % agreement_record['name'],
})
return super(Agreement, self).copy(id, default=default)
#api.multi
def unlink(self):
for agreement in self:
if any(agreement.mapped('order_line')):
raise exceptions.Warning(
_('You cannot remove agreements with confirmed orders!'))
self.unlink_orders(fields.Date.from_string(fields.Date.today()))
return models.Model.unlink(self)
#api.multi
def onchange_start_date(self, start_date=False):
if not start_date:
return {}
result = {'value': {'last_renovation_date': start_date}}
return result
#api.model
def revise_agreements_expirations_planned(self):
for agreement in self.search([('prolong', '=', 'unlimited')]):
if agreement.next_expiration_date <= fields.Date.today():
agreement.write({'prolong': 'unlimited'})
return True
#api.model
def _prepare_purchase_order_vals(self, agreement, date):
order_vals = {
'date_order': date,
'date_confirm': date,
'origin': agreement.number,
'partner_id': agreement.partner_id.id,
'state': 'draft',
'company_id': agreement.company_id.id,
'from_agreement': True,
'agreement_id': agreement.id,
'location_id': 1,
'fiscal_position_id': self.env['account.fiscal.position'].with_context(company_id=agreement.company_id.id).get_fiscal_position(agreement.partner_id.id),
'payment_term_id': agreement.partner_id.property_supplier_payment_term_id.id,
'currency_id': agreement.partner_id.property_purchase_currency_id.id or self.env.user.company_id.currency_id.id,
}
order_vals['user_id'] = agreement.partner_id.user_id.id
return order_vals
#api.model
def _prepare_purchase_order_line_vals(self, agreement_line, order):
product_lang = agreement_line.product_id.with_context({
'lang': order.partner_id.lang,
'partner_id': order.partner_id.id,
})
fpos = order.fiscal_position_id
order_line_vals = {
'order_id': order.id,
'product_id': agreement_line.product_id.id,
'product_qty': agreement_line.quantity,
'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'price_unit': 0.0,
'product_qty': 1.0,
'product_uom': agreement_line.product_id.uom_po_id.id or agreement_line.product_id.uom_id.id,
'name': product_lang.display_name,
'taxes_id': fpos.map_tax(agreement_line.product_id.supplier_taxes_id.filtered(lambda r: r.company_id.id == self.company_id.id))
}
if agreement_line.specific_price:
order_line_vals['price_unit'] = agreement_line.specific_price
order_line_vals['taxes_id'] = [(6, 0, tuple(order_line_vals['taxes_id']))]
if agreement_line.additional_description:
order_line_vals['name'] += " %s" % (
agreement_line.additional_description)
return order_line_vals
#api.multi
def create_order(self, date, agreement_lines):
self.ensure_one()
order_line_obj = self.env['purchase.order.line'].with_context(
company_id=self.company_id.id)
order_vals = self._prepare_purchase_order_vals(self, date)
order = self.env['purchase.order'].create(order_vals)
for agreement_line in agreement_lines:
order_line_vals = self._prepare_purchase_order_line_vals(
agreement_line, order)
order_line_obj.create(order_line_vals)
agreement_lines.write({'last_order_date': fields.Date.today()})
if self.state != 'orders':
self.state = 'orders'
return order
#api.multi
def _get_next_order_date(self, line, start_date):
self.ensure_one()
next_date = fields.Date.from_string(self.start_date)
while next_date <= start_date:
next_date = self.__get_next_term_date(
next_date, line.ordering_unit, line.ordering_interval)
return next_date
#api.multi
def generate_agreement_orders(self, start_date, end_date):
self.ensure_one()
if not self.active:
return
lines_to_order = {}
exp_date = fields.Date.from_string(self.next_expiration_date)
if exp_date < end_date and self.prolong != 'unlimited':
end_date = exp_date
for line in self.agreement_line:
if not line.active_chk:
continue
next_order_date = self._get_next_order_date(line, start_date)
while next_order_date <= end_date:
if not lines_to_order.get(next_order_date):
lines_to_order[next_order_date] = self.env[
'purchase.recurring_orders.agreement.line']
lines_to_order[next_order_date] |= line
next_order_date = self._get_next_order_date(
line, next_order_date)
dates = lines_to_order.keys()
dates.sort()
for date in dates:
order = self.order_line.filtered(
lambda x: (
fields.Date.to_string(
fields.Datetime.from_string(x.date_order)) ==
fields.Date.to_string(date)))
if not order:
self.create_order(
fields.Date.to_string(date), lines_to_order[date])
#api.multi
def generate_initial_order(self):
self.ensure_one()
agreement_lines = self.mapped('agreement_line').filtered('active_chk')
order = self.create_order(self.start_date, agreement_lines)
self.write({'state': 'first'})
order.signal_workflow('order_confirm')
return {
'domain': "[('id', '=', %s)]" % order.id,
'view_type': 'form',
'view_mode': 'form',
'res_model': 'purchase.order',
'context': self.env.context,
'res_id': order.id,
'view_id': [self.env.ref('purchase.purchase_order_form').id],
'type': 'ir.actions.act_window',
'nodestroy': True
}
#api.model
def generate_next_orders_planned(self, years=1, start_date=None):
if start_date:
start_date = fields.Date.from_string(start_date)
self.search([]).generate_next_orders(
years=years, start_date=start_date)
#api.multi
def generate_next_year_orders(self):
return self.generate_next_orders(years=1)
#api.multi
def generate_next_orders(self, years=1, start_date=None):
if not start_date:
start_date = fields.Date.from_string(fields.Date.today())
end_date = start_date + relativedelta(years=years)
for agreement in self:
agreement.generate_agreement_orders(start_date, end_date)
return True
#api.model
def confirm_current_orders_planned(self):
tomorrow = fields.Date.to_string(
fields.Date.from_string(fields.Date.today()) + timedelta(days=1))
orders = self.env['purchase.order'].search([
('agreement_id', '!=', False),
('state', 'in', ('draft', 'sent')),
('date_order', '<', tomorrow)
])
for order in orders:
order.signal_workflow('order_confirm')
#api.multi
def unlink_orders(self, start_date):
orders = self.mapped('order_line').filtered(
lambda x: (x.state in ('draft', 'sent') and
x.date_order >= start_date))
orders.unlink()
class AgreementLine(models.Model):
_name = 'purchase.recurring_orders.agreement.line'
uom_id = fields.Many2one('product_uom', string="Uom")
active_chk = fields.Boolean(
string='Active', default=True,
help='Unchecking this field, this quota is not generated')
agreement_id = fields.Many2one(
comodel_name='purchase.recurring_orders.agreement',
string='Agreement reference', ondelete='cascade')
product_id = fields.Many2one(
comodel_name='product.product', string='Product', ondelete='set null',
required=True)
name = fields.Char(
related="product_id.name", string='Description', store=False)
additional_description = fields.Char(
string='Add. description', size=30,
help='Additional description that will be added to the product '
'description on orders.')
quantity = fields.Float(
string='Quantity', required=True, help='Quantity of the product',
default=1.0)
discount = fields.Float(string='Discount (%)', digits=(16, 2))
ordering_interval = fields.Integer(
string='Interval', required=True, default=1,
help="Interval in time units for making an order of this product")
ordering_unit = fields.Selection(
selection=[('days', 'days'),
('weeks', 'weeks'),
('months', 'months'),
('years', 'years')],
string='Interval unit', required=True, default='months')
last_order_date = fields.Date(
string='Last order', help='Date of the last Purchase order generated')
specific_price = fields.Float(
string='Specific price', digits_compute=dp.get_precision('Purchase Price'),
help='Specific price for this product. Keep empty to use the list '
'price while generating order')
list_price = fields.Float(
related='product_id.list_price', string="List price", readonly=True)
_sql_constraints = [
('line_qty_zero', 'CHECK (quantity > 0)',
'All product quantities must be greater than 0.\n'),
('line_interval_zero', 'CHECK (ordering_interval > 0)',
'All ordering intervals must be greater than 0.\n'),
]
#api.multi
def onchange_product_id(self, product_id=False):
result = {}
if product_id:
product = self.env['product.product'].browse(product_id)
if product:
result['value'] = {'name': product['name']}
return result
class AgreementRenewal(models.Model):
_name = 'purchase.recurring_orders.agreement.renewal'
agreement_id = fields.Many2one(
comodel_name='purchase.recurring_orders.agreement',
string='Agreement reference', ondelete='cascade', select=True)
date = fields.Date(string='Date', help="Date of the renewal")
comments = fields.Char(
string='Comments', size=200, help='Renewal comments')
I have found that this post might be relevant for this issue:
https://github.com/adhoc-dev/odoo-addons/issues/113
I have suspected that this line:
'taxes_id': fpos.map_tax(agreement_line.product_id.supplier_taxes_id.filtered(lambda r: r.company_id.id == self.company_id.id))
might be the issue so I used a print statement:
print fpos.map_tax(agreement_line.product_id.supplier_taxes_id.filtered(lambda r: r.company_id.id == self.company_id.id))
account.tax(6,)
But I do not know how to continue further.
Any help/tip on where the issue could be is welcomed.
The below code
fpos.map_tax(agreement_line.product_id.supplier_taxes_id.filtered(lambda r: r.company_id.id == self.company_id.id))
returns a recordset but database doesn't store record set. that's why it fails with the message.
ProgrammingError: can't adapt type 'account.tax'
Solution
recordset.id // for singleton recordset
result : id (integer)
recordset.ids // for multi recordset
result : list of ids []
now it depends on which type of field you are going to write this value. If it is a Many2one field then it is supposed to be an integer. that you may get with recordset.id
NOTE 1 -
Be careful recordset can be recordsets that means mutliple records that will look like account.tax(6,7,12,34). In this case if you say recordset.id, it will fail because there are multiple Ids and it is not sure which one you want. So to get IDs from the recordset you can do recordset.ids that would result a list like [6,7,12,34] or [] in case a blank recordset.
NOTE2 -
If you were trying to write in a Many2many field. You can do something like
self.taxes_id = [(6,0, recordset.ids)]

How can i generate xls report in odoo

I want to generate my own excel report using Excel report engine in odoo 8. someone please send me a simple excel report sample or any helping URL. I'll be very thankful to you ....
Here is a simple piece of code. There is really a lot of examples on the internet with good explanations. I suggest you go through the code in detail to see how it works (by the way I have copied the code also from somewhere - I cannot remember where. Also have a look at the examples here:https://github.com/OCA/reporting-engine/tree/8.0
The version 8 branch also have a number of examples.
You can add columns by editing the "my_change" variable.
from openerp.osv import orm
from openerp.addons.report_xls.utils import rowcol_to_cell, _render
from openerp.tools.translate import _
class account_move_line(orm.Model):
_inherit = 'abc.salesforecast'
# override list in custom module to add/drop columns or change order
def _report_xls_fields(self, cr, uid, context=None):
return [
'contract', 'proposal', 'description',
#'amount_currency', 'currency_name',
]
# Change/Add Template entries
def _report_xls_template(self, cr, uid, context=None):
"""
Template updates, e.g.
my_change = {
'move':{
'header': [1, 20, 'text', _('My Move Title')],
'lines': [1, 0, 'text', _render("line.move_id.name or ''")],
'totals': [1, 0, 'text', None]},
}
return my_change
"""
return {}
The code for the parser is as follows.
import xlwt
import time
from datetime import datetime
from openerp.osv import orm
from openerp.report import report_sxw
from openerp.addons.report_xls.report_xls import report_xls
from openerp.addons.report_xls.utils import rowcol_to_cell, _render
from openerp.tools.translate import translate, _
from openerp import pooler
import logging
_logger = logging.getLogger(__name__)
class contract_sales_forecast_xls_parser(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(contract_sales_forecast_xls_parser, self).__init__(cr, uid, name, context=context)
forecast_obj = self.pool.get('msr.salesforecast')
self.context = context
wanted_list = forecast_obj._report_xls_fields(cr, uid, context)
template_changes = forecast_obj._report_xls_template(cr, uid, context)
self.localcontext.update({
'datetime': datetime,
'wanted_list': wanted_list,
'template_changes': template_changes,
'_': self._,
})
def _(self, src):
lang = self.context.get('lang', 'en_US')
return translate(self.cr, _ir_translation_name, 'report', lang, src) or src
class contract_sales_forecast_xls(report_xls):
def __init__(self, name, table, rml=False, parser=False, header=True, store=False):
super(contract_sales_forecast_xls, self).__init__(name, table, rml, parser, header, store)
# Cell Styles
_xs = self.xls_styles
# header
rh_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all']
self.rh_cell_style = xlwt.easyxf(rh_cell_format)
self.rh_cell_style_center = xlwt.easyxf(rh_cell_format + _xs['center'])
self.rh_cell_style_right = xlwt.easyxf(rh_cell_format + _xs['right'])
# lines
aml_cell_format = _xs['borders_all']
self.aml_cell_style = xlwt.easyxf(aml_cell_format)
self.aml_cell_style_center = xlwt.easyxf(aml_cell_format + _xs['center'])
self.aml_cell_style_date = xlwt.easyxf(aml_cell_format + _xs['left'], num_format_str = report_xls.date_format)
self.aml_cell_style_decimal = xlwt.easyxf(aml_cell_format + _xs['right'], num_format_str = report_xls.decimal_format)
# totals
rt_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all']
self.rt_cell_style = xlwt.easyxf(rt_cell_format)
self.rt_cell_style_right = xlwt.easyxf(rt_cell_format + _xs['right'])
self.rt_cell_style_decimal = xlwt.easyxf(rt_cell_format + _xs['right'], num_format_str = report_xls.decimal_format)
# XLS Template
self.col_specs_template = {
'contract':{
'header': [1, 20, 'text', _render("_('Contract Number')")],
'lines': [1, 0, 'text', _render("msr_contract_id or ''")],
'totals': [1, 0, 'text', None]},
'proposal':{
'header': [1, 42, 'text', _render("_('Proposal Number')")],
'lines': [1, 0, 'text', _render("msr_proposal or ''")],
'totals': [1, 0, 'text', None]},
'description':{
'header': [1, 42, 'text', _render("_('Description')")],
'lines': [1, 0, 'text', _render("name or ''")],
'totals': [1, 0, 'text', None]},
}
def generate_xls_report(self, _p, _xs, data, objects, wb):
wanted_list = _p.wanted_list
self.col_specs_template.update(_p.template_changes)
_ = _p._
#report_name = objects[0]._description or objects[0]._name
report_name = _("Sales forecast from current contracts")
ws = wb.add_sheet(report_name[:31])
ws.panes_frozen = True
ws.remove_splits = True
ws.portrait = 0 # Landscape
ws.fit_width_to_pages = 1
row_pos = 0
# set print header/footer
ws.header_str = self.xls_headers['standard']
ws.footer_str = self.xls_footers['standard']
# Title
cell_style = xlwt.easyxf(_xs['xls_title'])
c_specs = [
('report_name', 1, 0, 'text', report_name),
]
row_data = self.xls_row_template(c_specs, ['report_name'])
row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=cell_style)
row_pos += 1
# Column headers
c_specs = map(lambda x: self.render(x, self.col_specs_template, 'header', render_space={'_': _p._}), wanted_list)
row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs])
row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.rh_cell_style, set_column_size=True)
ws.set_horz_split_pos(row_pos)
# account move lines
for line in objects:
c_specs = map(lambda x: self.render(x, self.col_specs_template, 'lines'), wanted_list)
row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs])
row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.aml_cell_style)
# Totals
contract_sales_forecast_xls('report.contract.sales.forecast.xls',
'abc.salesforecast',
parser="contract_sales_forecast_xls_parser")
The xml file will look as follows to setup the necessary actions etc.
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="action_contract_sales_forecast_xls" model="ir.actions.report.xml">
<field name="name">Export Selected Lines To Excel</field>
<field name="model">abc.salesforecast</field>
<field name="type">ir.actions.report.xml</field>
<field name="report_name">contract.sales.forecast.xls</field>
<field name="report_type">xls</field>
<field name="auto" eval="False"/>
</record>
<record model="ir.values" id="contract_sales_forecast_xls_values">
<field name="name">Export Selected Lines</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.report.xml,' +str(ref('action_contract_sales_forecast_xls'))" />
<field name="model">abc.salesforecast</field>
</record>
</data>
</openerp>
A second example. First the xml to create a button. This is only an extract.
<form string = "Contract Search Wizard" version="7.0">
<sheet>
<group>
<button icon="gtk-ok" name="print_contract_list" string="Print Contract List" type="object" />
<button icon="gtk-ok" name="export_contract_product" string="Export Contract vs. Product Pivot Table" type="object" />
<button icon="gtk-ok" name="export_contract_country" string="Export Contract vs. Country Pivot Table" type="object" />
<button icon="gtk-cancel" special="cancel" string="Cancel" />
</group>
</sheet>
</form>
The below code is a wizard with several buttons. I removed some code to save space. The report is activated from a button:
class abc_contract_search_wizard(osv.osv):
def _prd_report_xls_fields(self, cr, uid, context=None):
SQLstring = "SELECT abc_product_list.name FROM abc_product_list;"
cr.execute(SQLstring)
tbl_products = cr.dictfetchall()
header_list=['contract_id','contract_name','exclusive']
for t in tbl_products:
header_list.append(t['name'])
return header_list
# Change/Add Template entries
def _prd_report_xls_template(self, cr, uid, context=None):
"""
Template updates, e.g.
my_change = {
'move':{
'header': [1, 20, 'text', _('My Move Title')],
'lines': [1, 0, 'text', _render("line.move_id.name or ''")],
'totals': [1, 0, 'text', None]},
}
return my_change
"""
SQLstring = "SELECT abc_product_list.name FROM abc_product_list;"
cr.execute(SQLstring)
tbl_products = cr.dictfetchall()
abc_tmpl = {
'contract_id':
{
'header':[1,20, 'text', _render("_('Contract ID')")],
'lines':[1,0, 'text', _render("line.abc_contract_id.name or ''")],
'totals':[1, 0, 'text', None],
},
'contract_name' :
{
'header':[1,40, 'text', _render("_('Contract Name')")],
'lines':[1,0, 'text', _render("line.abc_contract_name or ''")],
'totals':[1, 0, 'text', None],
},
'exclusive':
{
'header':[1,10, 'text', _render("_('Exlusive')")],
'lines':[1,0, 'text', _render("line.abc_country.name or ''")],
'totals':[1, 0, 'text', None],
},
}
for t in tbl_products:
abc_tmpl[t['name']]={
'header':[1,3, 'text', _render("_('" + t['name']+"')")],
'lines':[1,0, 'text', _render("line.abc_contract_id.name or ''")],
'totals':[1, 0, 'text', None],
}
return abc_tmpl
_name='abc.contract.search.wizard'
_columns={
'country':fields.many2one('abc.countries','Country'),
'product':fields.many2one('abc.product.list','Product'),
'start_date':fields.date('Start Date'),
'end_date':fields.date('End Date'),
'partner':fields.many2one('res.partner','Partner'),
'product_type':fields.many2one('abc.product.type','Product Type'),
'regions':fields.many2one('abc.regions', 'Regions'),
'exclusive':fields.boolean('Exclusive'),
'contract_type':fields.many2one('abc.contract.types','Contract Type'),
}
def find_product(self, tbl_contractproducts, product_id):
is_there=False
for t in tbl_contractproducts:
if product_id==t['product_id']:
is_there=True
return is_there
def get_contract_products(self, cr, uid, ids, context, contract_id, tbl_products):
products={}
SQLstring = "SELECT abc_contract_product_list.product_id, abc_contract_product_list.contract_id FROM abc_contract_product_list " \
+ "WHERE (((abc_contract_product_list.contract_id) =" + str(contract_id) + "));"
cr.execute(SQLstring)
tbl_contractproducts = cr.dictfetchall()
for t in tbl_products:
if self.find_product(tbl_contractproducts,t['product_id']):
products[t['product_name']]='X'
else:
products[t['product_name']]=''
return products
def export_contract_product(self, cr, uid, ids, context=None):
rst = self.browse(cr, uid, ids)[0]
country_id = rst.country.id
product_id = rst.product.id
start_date = rst.start_date
end_date = rst.end_date
product_type_id = rst.product_type.id
partner_id = rst.partner.id
region_id = rst.regions.id
exclusive = rst.exclusive
contract_type_id = rst.contract_type.id
SQLwhere = ""
SQLstring = "SELECT DISTINCT abc_official_documents.id, abc_official_documents.contract_id, abc_official_documents.name AS doc_name, abc_official_documents.contract_exclusive_agreemnet " \
+ "FROM res_partner INNER JOIN (((abc_contract_countries INNER JOIN (((abc_contract_product_list INNER JOIN (abc_product_type INNER JOIN abc_product_list " \
+ "ON abc_product_type.id = abc_product_list.product_type) ON abc_contract_product_list.product_id = abc_product_list.id) INNER JOIN abc_official_documents ON "\
+ "abc_contract_product_list.contract_id = abc_official_documents.id) INNER JOIN abc_contract_types ON abc_official_documents.contract_type = abc_contract_types.id) "\
+ "ON abc_contract_countries.contract_id = abc_official_documents.id) INNER JOIN abc_countries ON abc_contract_countries.country_id = abc_countries.id) INNER JOIN "\
+ "abc_regions ON abc_countries.country_region = abc_regions.id) ON res_partner.id = abc_official_documents.contract_partner_id "
if country_id:
SQLwhere = " AND ((abc_contract_countries.country_id) = " + str(country_id) + ")"
if product_id:
SQLwhere = SQLwhere + " AND ((abc_contract_product_list.product_id) = " + str(product_id) + ")"
if start_date:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_start_date) < " + str(start_date) + ")"
if end_date:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_termination_date) < " + str(end_date) + ")"
if partner_id:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_partner_id) = " + str(partner_id) +")"
if region_id:
SQLwhere = SQLwhere + " AND ((abc_countries.country_region) = " + str(region_id) + ")"
if exclusive:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_exclusive_agreemnet) = true )"
if contract_type_id:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_type) = " + str(contract_type_id) + ")"
if product_type_id:
SQLwhere = SQLwhere + " AND ((abc_product_list.product_type) = " +str(product_type_id) + ")"
SQLwhere = SQLwhere[-(len(SQLwhere)-5):] #Vat die eerste "AND" weg (5 karakters)
if ((not SQLwhere) | (len(SQLwhere)==0)):
SQLstring = SQLstring + " LIMIT 100;"
else:
SQLstring = SQLstring + "WHERE (" + SQLwhere + ") LIMIT 100;"
cr.execute(SQLstring)
tblContracts = cr.dictfetchall()
SQLstring = "SELECT abc_product_list.id AS product_id, abc_product_list.name as product_name FROM abc_product_list;"
cr.execute(SQLstring)
tbl_products = cr.dictfetchall()
pivot_table = []
datas={'ids':context.get('active_ids', [])}
for t in tblContracts:
if t:
if t['contract_exclusive_agreemnet']:
excl="Yes"
else:
excl = "No"
contract_table = {
'contract_id': t['contract_id'],
'contract_name': t['doc_name'],
'exclusive':excl,
}
product_table=self.get_contract_products(cr, uid, ids, context, t['id'], tbl_products)
full_table = dict(contract_table.items() + product_table.items())
pivot_table.append(full_table)
datas['contract_list']= pivot_table
return {
'type':'ir.actions.report.xml',
'report_name': 'contract_products',
'datas':datas,
}
abc_contract_search_wizard()
Here is the code for the parser:
class contract_products_parser(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(contract_products_parser, self).__init__(cr, uid, name, context=context)
forc_obj = self.pool.get('abc.contract.search.wizard')
self.context = context
wanted_list = forc_obj._prd_report_xls_fields(cr, uid, context)
template_changes = forc_obj._prd_report_xls_template(cr, uid, context)
self.localcontext.update({
'datetime': datetime,
'wanted_list': wanted_list,
'template_changes': template_changes,
'_': self._,
})
def _(self, src):
lang = self.context.get('lang', 'en_US')
return translate(self.cr, _ir_translation_name, 'report', lang, src) or src
class contract_products_xls(report_xls):
def __init__(self, name, table, rml=False, parser=False, header=True, store=False):
super(contract_products_xls, self).__init__(name, table, rml, parser, header, store)
# Cell Styles
_xs = self.xls_styles
# header
rh_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all']
self.rh_cell_style = xlwt.easyxf(rh_cell_format)
self.rh_cell_style_center = xlwt.easyxf(rh_cell_format + _xs['center'])
self.rh_cell_style_right = xlwt.easyxf(rh_cell_format + _xs['right'])
# lines
aml_cell_format = _xs['borders_all']
self.aml_cell_style = xlwt.easyxf(aml_cell_format)
self.aml_cell_style_center = xlwt.easyxf(aml_cell_format + _xs['center'])
self.aml_cell_style_date = xlwt.easyxf(aml_cell_format + _xs['left'], num_format_str = report_xls.date_format)
self.aml_cell_style_decimal = xlwt.easyxf(aml_cell_format + _xs['right'], num_format_str = report_xls.decimal_format)
# totals
rt_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all']
self.rt_cell_style = xlwt.easyxf(rt_cell_format)
self.rt_cell_style_right = xlwt.easyxf(rt_cell_format + _xs['right'])
self.rt_cell_style_decimal = xlwt.easyxf(rt_cell_format + _xs['right'], num_format_str = report_xls.decimal_format)
self.col_specs_template = {
}
def get_c_specs(self, wanted, col_specs, rowtype, data):
"""
returns 'evaluated' col_specs
Input:
- wanted: element from the wanted_list
- col_specs : cf. specs[1:] documented in xls_row_template method
- rowtype : 'header' or 'data'
- render_space : type dict, (caller_space + localcontext)
if not specified
"""
row = col_specs[wanted][rowtype][:]
row[3]=data[wanted]
row.insert(0, wanted)
return row
return True
def new_xls_write_row(self, ws, row_pos, row_data, header, headrot_style, dark_style,
row_style=default_style, set_column_size=False ):
r = ws.row(row_pos)
orig_style=row_style
for col, size, spec in row_data:
data = spec[4]
if header:
if (col!=0) & (col!=1) & (col!=2):
row_style=headrot_style #+ 'align: rotation 90;'
else:
if data=="X":
row_style=dark_style #+ 'pattern: pattern solid, fore_color 0;'
else:
row_style=orig_style
formula = spec[5].get('formula') and \
xlwt.Formula(spec[5]['formula']) or None
style = spec[6] and spec[6] or row_style
if not data:
# if no data, use default values
data = report_xls.xls_types_default[spec[3]]
if size != 1:
if formula:
ws.write_merge(
row_pos, row_pos, col, col + size - 1, data, style)
else:
ws.write_merge(
row_pos, row_pos, col, col + size - 1, data, style)
else:
if formula:
ws.write(row_pos, col, formula, style)
else:
spec[5]['write_cell_func'](r, col, data, style)
if set_column_size:
ws.col(col).width = spec[2] * 256
return row_pos + 1
def generate_xls_report(self, _p, _xs, data, objects, wb):
wanted_list = _p.wanted_list
self.col_specs_template.update(_p.template_changes)
_ = _p._
#report_name = objects[0]._description or objects[0]._name
report_name = _("Export Contract Countries")
ws = wb.add_sheet(report_name[:31])
ws.panes_frozen = True
ws.remove_splits = True
ws.portrait = 0 # Landscape
ws.fit_width_to_pages = 1
row_pos = 0
_xs = self.xls_styles
headrot_style = _xs['bold'] + _xs['fill'] + _xs['borders_all'] + 'align: rotation 90'
xlwt_headrot=xlwt.easyxf(headrot_style)
dark_style = _xs['borders_all']+'pattern: pattern solid, fore_color 0;'
#self.rh_cell_style = xlwt.easyxf(rh_cell_format)
#self.rh_cell_style_center = xlwt.easyxf(rh_cell_format + _xs['center'])
# set print header/footer
ws.header_str = self.xls_headers['standard']
ws.footer_str = self.xls_footers['standard']
# Title
cell_style = xlwt.easyxf(_xs['xls_title'])
c_specs = [
('report_name', 1, 0, 'text', report_name),
]
row_data = self.xls_row_template(c_specs, ['report_name'])
row_pos = self.new_xls_write_row(ws, row_pos, row_data, False, xlwt_headrot , xlwt.easyxf(dark_style), row_style=cell_style )
row_pos += 1
# Column headers
c_specs = map(lambda x: self.render(x, self.col_specs_template, 'header', render_space={'_': _p._}), wanted_list)
row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs])
row_pos = self.new_xls_write_row(ws, row_pos, row_data, True, xlwt_headrot, xlwt.easyxf(dark_style), row_style=self.rh_cell_style, set_column_size=True)
ws.set_horz_split_pos(row_pos)
# account move lines
for line in data['contract_list']:
c_specs = map(lambda x: self.get_c_specs(x, self.col_specs_template, 'lines', line), wanted_list)
row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs])
row_pos = self.new_xls_write_row(ws, row_pos, row_data, False, xlwt_headrot, xlwt.easyxf(dark_style), row_style=self.aml_cell_style)
contract_products_xls('report.contract_products',
'abc.contract.search.wizard',
parser=contract_products_parser)
To Create an Excel file or a spreadsheet
“import xlwt” package functionality to create sheet in your Py file.We can define the title, header, number, date, and normal style using xlwt.easyxf().
For example title style is given below
new_style = xlwt.easyxf(‘font:height 230; align: wrap No;border: top thick;border: bottom thick;’)
Define how the border should appear.define the workbook. Workbook is actually what we view in our spreadsheet.
To define workbook,
wbk = xlwt.Workbook()
sheet = wbk.add_sheet(‘New_sheet’, cell_overwrite_ok=True)
for write in to the sheet
sheet.write(4, 4, ‘Spellbound Soft Solution’,font_size)
To change the width and height of a cell,
sheet.col(1).width = 500*12
sheet.row(5).height = 70*5
for more goto :
http://spellboundss.com/xls-report-in-odoo/
Thanks
Simply add this report_xlsx module from the app store.
your_module_name --> report--> my_report.py
your_module_name --> report--> my_report.xml
my_report.py
try:
from openerp.addons.report_xlsx.report.report_xlsx import ReportXlsx
except ImportError:
class ReportXlsx(object):
def __init__(self, *args, **kwargs):
pass
class PartnerXlsx(ReportXlsx):
def generate_xlsx_report(self, workbook, data, partners):
for obj in partners:
report_name = obj.name
# One sheet by partner
sheet = workbook.add_worksheet(report_name[:31])
bold = workbook.add_format({'bold': True})
sheet.write(0, 0, obj.name, bold)
PartnerXlsx('report.res.partner.xlsx', 'res.partner')
my_report.xml
`<report
id="partner_xlsx"
model="res.partner"
string="Print to XLSX"
report_type="xlsx"
name="res.partner.xlsx"
file="res.partner.xlsx"
attachment_use="False"
/>`

product_id_change return can't update fields.selection to form

product_id_change return can't update form of fields.selection...?
columns={
'expr_date':fields.selection('Expire Date',type='selection'),}
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False,
lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
lang = lang or context.get('lang', False)
if not partner_id:
raise osv.except_osv(_('No Customer Defined!'), _('Before choosing a product,\n select a customer in the sales form.'))
warning = {}
product_uom_obj = self.pool.get('product.uom')
partner_obj = self.pool.get('res.partner')
product_obj = self.pool.get('product.product')
context = {'lang': lang, 'partner_id': partner_id}
if partner_id:
lang = partner_obj.browse(cr, uid, partner_id).lang
context_partner = {'lang': lang, 'partner_id': partner_id}
if not product:
return {'value': {'th_weight': 0,
'product_uos_qty': qty}, 'domain': {'product_uom': [],
'product_uos': []}}
if not date_order:
date_order = time.strftime(DEFAULT_SERVER_DATE_FORMAT)
result = {}
warning_msgs = ''
product_obj = product_obj.browse(cr, uid, product, context=context_partner)
uom2 = False
if uom:
uom2 = product_uom_obj.browse(cr, uid, uom)
if product_obj.uom_id.category_id.id != uom2.category_id.id:
uom = False
if uos:
if product_obj.uos_id:
uos2 = product_uom_obj.browse(cr, uid, uos)
if product_obj.uos_id.category_id.id != uos2.category_id.id:
uos = False
else:
uos = False
fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False
if update_tax: # The quantity only have changed
result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, product_obj.taxes_id)
if not flag:
result['name'] = self.pool.get('product.product').name_get(cr, uid, [product_obj.id], context=context_partner)[0][1]
if product_obj.description_sale:
result['name'] += '\n' + product_obj.description_sale
domain = {}
if (not uom) and (not uos):
result['product_uom'] = product_obj.uom_id.id
if product_obj.uos_id:
result['product_uos'] = product_obj.uos_id.id
result['product_uos_qty'] = qty * product_obj.uos_coeff
uos_category_id = product_obj.uos_id.category_id.id
else:
result['product_uos'] = False
result['product_uos_qty'] = qty
uos_category_id = False
result['th_weight'] = qty * product_obj.weight
domain = {'product_uom':
[('category_id', '=', product_obj.uom_id.category_id.id)],
'product_uos':
[('category_id', '=', uos_category_id)]}
elif uos and not uom: # only happens if uom is False
result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id
result['product_uom_qty'] = qty_uos / product_obj.uos_coeff
result['th_weight'] = result['product_uom_qty'] * product_obj.weight
elif uom: # whether uos is set or not
default_uom = product_obj.uom_id and product_obj.uom_id.id
q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom)
if product_obj.uos_id:
result['product_uos'] = product_obj.uos_id.id
result['product_uos_qty'] = qty * product_obj.uos_coeff
else:
result['product_uos'] = False
result['product_uos_qty'] = qty
result['th_weight'] = q * product_obj.weight # Round the quantity up
if not uom2:
uom2 = product_obj.uom_id
# get unit price
if not pricelist:
warn_msg = _('You have to select a pricelist or a customer in the sales form !\n'
'Please set one before choosing a product.')
warning_msgs += _("No Pricelist ! : ") + warn_msg + "\n\n"
else:
price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist],
product, qty or 1.0, partner_id, {
'uom': uom or result.get('product_uom'),
'date': date_order,
})[pricelist]
if price is False:
warn_msg = _("Cannot find a pricelist line matching this product and quantity.\n"
"You have to change either the product, the quantity or the pricelist.")
warning_msgs += _("No valid pricelist line found ! :") + warn_msg + "\n\n"
else:
result.update({'price_unit': price})
cr.execute("select s.expr_date from stock_move s where s.product_id= %s", (product,))
date_all=[]
data=cr.fetchall()
print data
for date in data:
date_all.append((' ',date))
result.update({'expr_date':date_all})
print 'Expr Date is ..................',result
if warning_msgs:
warning = {
'title': _('Configuration Error!'),
'message' : warning_msgs
}
return {'value':result, 'domain': domain, 'warning': warning}

indent using condition

please help me..what's wrong
def _amount_all(self, cr, uid, ids, name, args, context=None):
res = {}
for invoice in self.browse(cr, uid, ids, context=context):
res[invoice.id] = {
'amount_untaxed': 0.0,
'amount_tax': 0.0,
'amount_total': 0.0
}
for line in invoice.invoice_line:
res[invoice.id]['amount_untaxed'] += line.price_subtotal
for line in invoice.tax_line:
res[invoice.id]['amount_tax'] += line.amount
res[invoice.id]['amount_total'] = res[invoice.id]['amount_tax'] + res[invoice.id]['amount_untaxed']
cr.execute('select payment from sale_order where name = %s',(invoice.origin,))
ads = cr.fetchone()
pay = ads and ads[0] or None
if pay == 'deposit':
if invoice.partner_id.avail < 0:
raise osv.except_osv(_('Invalid action !'), _('Deposit must be recharged')
if invoice.amount_total != res[invoice.id]['amount_total']:
temp = invoice.partner_id.depot - res[invoice.id]['amount_total']
cr.execute('update res_partner set depot=%s where id = %s', (temp, invoice.partner_id.id,))
return res
I checked the condition that if he paid using a deposit and is available if less than zero if not then deposit reduction is done. I think..this is correct..but when I running, appear like this
if invoice.amount_total != res[invoice.id]['amount_total']:
SyntaxError: invalid syntax
Why have you given 2tabs(8 spaces) after the line raise osv.except_osv()
Your code should be like
def _amount_all(self, cr, uid, ids, name, args, context=None):
res = {}
for invoice in self.browse(cr, uid, ids, context=context):
res[invoice.id] = {
'amount_untaxed': 0.0,
'amount_tax': 0.0,
'amount_total': 0.0
}
for line in invoice.invoice_line:
res[invoice.id]['amount_untaxed'] += line.price_subtotal
for line in invoice.tax_line:
res[invoice.id]['amount_tax'] += line.amount
res[invoice.id]['amount_total'] = res[invoice.id]['amount_tax'] + res[invoice.id]['amount_untaxed']
cr.execute('select payment from sale_order where name = %s',(invoice.origin,))
ads = cr.fetchone()
pay = ads and ads[0] or None
if pay == 'deposit':
if invoice.partner_id.avail < 0:
raise osv.except_osv(_('Invalid action !'), _('Deposit must be recharged')
if invoice.amount_total != res[invoice.id]['amount_total']:
temp = invoice.partner_id.depot - res[invoice.id]['amount_total']
cr.execute('update res_partner set depot=%s where id = %s', (temp, invoice.partner_id.id,))
return res