I have created a function which is working fine if i use it through the view. but it's not working on schedule action, in openerp log show the following error.
TypeError: old_api() takes at least 4 arguments (3 given)
My module
class account_invoice(models.Model):
_name = 'account.invoice'
_rec_name = 'invoice_number'
#api.multi
def create_invoice(self):
id = self.id
amount = 0
journal = self.env['journal.entry']
for credit in self.invoice_line:
fee = credit.amount * credit.qty
if credit.account.parent.type.name == "Revenue":
journal.sudo().create({'account': credit.account.id,
'credit': fee,
'student_id' : self.student_id.id})
For method to work as a scheduled action you should call it with #api.model decorator instead of #api.multi, which works with view buttons.
Related
I scheduled an cron that execute every 1st of the month, the purpose is to allocate leave for all employee according to their tags. here is sample of my code :
for leave in leave_type_ids:
for employee_tag in employee_tag_ids:
values = {
'name': 'Allocation mensuelle %s %s' % (now.strftime('%B'), now.strftime('%Y')),
'holiday_status_id': leave.id,
'number_of_days': employee_tag.allocation,
'holiday_type': 'category',
'category_id': employee_tag.id,
}
try:
self.create(values).action_approve()
except Exception as e:
_logger.critical(e)
I want to point out that self is instance of 'hr.leave.allocation'.
The problem is when I create the record, the field employee_id is automatically fill with the user/employee OdooBot (the one who executed the program in the cron) and that is not all, the employee OdooBot was allocated a leaves.
This behavior is due to those codes in odoo native modules :
def _default_employee(self):
return self.env.context.get('default_employee_id') or self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
employee_id = fields.Many2one(
'hr.employee', string='Employee', index=True, readonly=True,
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, default=_default_employee, track_visibility='onchange')
So my question is how to prevent this when it's the cron and set it to normal when it's in Form view?
The field "employé" should be empty here (in image below), because it is an allocation by tag.
You must loop over hr.employee because then you can do either of the following:
self.with_context({'default_employee_id': employee.id}).create(...)
OR
self.sudo(employee.id).create(...)
I'm not sure if the title accurately describes what I'm trying to do. I have a Python3.x script that I wrote that will issue flood warning to my facebook page when the river near my home has reached it's lowest flood stage. Right now the script works, however it only reports data from one measuring station. I would like to be able to process the data from all of the stations in my county (total of 5), so I was thinking that maybe a class method may do the trick but I'm not sure how to implement it. I've been teaching myself Python since January and feel pretty comfortable with the language for the most part, and while I have a good idea of how to build a class object I'm not sure how my flow chart should look. Here is the code now:
#!/usr/bin/env python3
'''
Facebook Flood Warning Alert System - this script will post a notification to
to Facebook whenever the Sabine River # Hawkins reaches flood stage (22.3')
'''
import requests
import facebook
from lxml import html
graph = facebook.GraphAPI(access_token='My_Access_Token')
river_url = 'http://water.weather.gov/ahps2/river.php?wfo=SHV&wfoid=18715&riverid=203413&pt%5B%5D=147710&allpoints=143204%2C147710%2C141425%2C144668%2C141750%2C141658%2C141942%2C143491%2C144810%2C143165%2C145368&data%5B%5D=obs'
ref_url = 'http://water.weather.gov/ahps2/river.php?wfo=SHV&wfoid=18715&riverid=203413&pt%5B%5D=147710&allpoints=143204%2C147710%2C141425%2C144668%2C141750%2C141658%2C141942%2C143491%2C144810%2C143165%2C145368&data%5B%5D=all'
def checkflood():
r = requests.get(river_url)
tree = html.fromstring(r.content)
stage = ''.join(tree.xpath('//div[#class="stage_stage_flow"]//text()'))
warn = ''.join(tree.xpath('//div[#class="current_warns_statmnts_ads"]/text()'))
stage_l = stage.split()
level = float(stage_l[2])
#check if we're at flood level
if level < 22.5:
pass
elif level == 37:
major_diff = level - 23.0
major_r = ('The Sabine River near Hawkins, Tx has reached [Major Flood Stage]: #', stage_l[2], 'Ft. ', str(round(major_diff, 2)), ' Ft. \n Please click the link for more information.\n\n Current Warnings and Alerts:\n ', warn)
major_p = ''.join(major_r)
graph.put_object(parent_object='me', connection_name='feed', message = major_p, link = ref_url)
<--snip-->
checkflood()
Each station has different 5 different catagories for flood stage: Action, Flood, Moderate, Major, each different depths per station. So for Sabine river in Hawkins it will be Action - 22', Flood - 24', Moderate - 28', Major - 32'. For the other statinos those depths are different. So I know that I'll have to start out with something like:
class River:
def __init__(self, id, stage):
self.id = id #station ID
self.stage = stage #river level'
#staticmethod
def check_flood(stage):
if stage < 22.5:
pass
elif stage.....
but from there I'm not sure what to do. Where should it be added in(to?) the code, should I write a class to handle the Facebook postings as well, is this even something that needs a class method to handle, is there any way to clean this up for efficiency? I'm not looking for anyone to write this up for me, but some tips and pointers would sure be helpful. Thanks everyone!
EDIT Here is what I figured out and is working:
class River:
name = ""
stage = ""
action = ""
flood = ""
mod = ""
major = ""
warn = ""
def checkflood(self):
if float(self.stage) < float(self.action):
pass
elif float(self.stage) >= float(self.major):
<--snip-->
mineola = River()
mineola.name = stations[0]
mineola.stage = stages[0]
mineola.action = "13.5"
mineola.flood = "14.0"
mineola.mod = "18.0"
mineola.major = "21.0"
mineola.alert = warn[0]
hawkins = River()
hawkins.name = stations[1]
hawkins.stage = stages[1]
hawkins.action = "22.5"
hawkins.flood = "23.0"
hawkins.mod = "32.0"
hawkins.major = "37.0"
hawkins.alert = warn[1]
<--snip-->
So from here I'm tring to stick all the individual river blocks into one block. What I have tried so far is this:
class River:
... name = ""
... stage = ""
... def testcheck(self):
... return self.name, self.stage
...
>>> for n in range(num_river):
... stations[n] = River()
... stations[n].name = stations[n]
... stations[n].stage = stages[n]
...
>>> for n in range(num_river):
... stations[n].testcheck()
...
<__main__.River object at 0x7fbea469bc50> 4.13
<__main__.River object at 0x7fbea46b4748> 20.76
<__main__.River object at 0x7fbea46b4320> 22.13
<__main__.River object at 0x7fbea46b4898> 16.08
So this doesn't give me the printed results that I was expecting. How can I return the string instead of the object? Will I be able to define the Class variables in this manner or will I have to list them out individually? Thanks again!
After reading many, many, many articles and tutorials on class objects I was able to come up with a solution for creating the objects using list elements.
class River():
def __init__(self, river, stage, flood, action):
self.river = river
self.stage = stage
self.action = action
self.flood = flood
self.action = action
def alerts(self):
if float(self.stage < self.flood):
#alert = "The %s is below Flood Stage (%sFt) # %s Ft. \n" % (self.river, self.flood, self.stage)
pass
elif float(self.stage > self.flood):
alert = "The %s has reached Flood Stage(%sFt) # %sFt. Warnings: %s \n" % (self.river, self.flood, self.stage, self.action)
return alert
'''this is the function that I was trying to create
to build the class objects automagically'''
def riverlist():
river_list = []
for n in range(len(rivers)):
station = River(river[n], stages[n], floods[n], warns[n])
river_list.append(station)
return river_list
if __name__ == '__main__':
for x in riverlist():
print(x.alerts())
What i am trying to achieve
Write a scheduler, that uses a database to schedule similar tasks at different timings.
For the same i am using celery beat, the code snippet below would give an idea
try:
reader = MongoReader()
except:
raise
try:
tasks = reader.get_scheduled_tasks()
except:
raise
celerybeat_schedule = dict()
for task in tasks:
celerybeat_schedule[task["task_id"]] =dict()
celerybeat_schedule[task["task_id"]]["task"] = task["task_name"]
celerybeat_schedule[task["task_id"]]["args"] = (task,)
celerybeat_schedule[task["task_id"]]["schedule"] = get_task_schedule(task)
app.conf.update(BROKER_URL=rabbit_mq_endpoint, CELERY_TASK_SERIALIZER='json', CELERY_ACCEPT_CONTENT=['json'], CELERYBEAT_SCHEDULE=celerybeat_schedule)
so these are three steps
- reading all tasks from datastore
- creating a dictionary, celery scheduler which is populated by all tasks having properties, task_name(method that would run), parameters(data to pass to the method), schedule(stores when to run)
- updating this with celery configurations
Expected scenario
given all entries run the same celery task name that just prints, have same schedule to be run every 5 min, having different parameters specifying what to print, lets say db has
task name , parameter , schedule
regular_print , Hi , {"minutes" : 5}
regular_print , Hello , {"minutes" : 5}
regular_print , Bye , {"minutes" : 5}
I expect, these to be printing every 5 minutes to print all three
What happens
Only one of Hi, Hello, Bye prints( possible randomly, surely not in sequence)
Please help,
Thanks a lot in advance :)
Was able to resolve this using version 4 of celery. Sample similar to what worked for me.. can also find in documentation by celery for version 4
#taking address and user-pass from environment(you can mention direct values)
ex_host_queue = os.environ["EX_HOST_QUEUE"]
ex_port_queue = os.environ["EX_PORT_QUEUE"]
ex_user_queue = os.environ["EX_USERID_QUEUE"]
ex_pass_queue = os.environ["EX_PASSWORD_QUEUE"]
broker= "amqp://"+ex_user_queue+":"+ex_pass_queue+"#"+ex_host_queue+":"+ex_port_queue+"//"
#celery initialization
app = Celery(__name__,backend=broker, broker=broker)
app.conf.task_default_queue = 'scheduler_queue'
app.conf.update(
task_serializer='json',
accept_content=['json'], # Ignore other content
result_serializer='json'
)
task = {"task_id":1,"a":10,"b":20}
##method to update scheduler
def add_scheduled_task(task):
print("scheduling task")
del task["_id"]
print("adding task_id")
name = task["task_name"]
app.add_periodic_task(timedelta(minutes=1),add.s(task), name = task["task_id"])
#app.task(name='scheduler_task')
def scheduler_task(data):
print(str(data["a"]+data["b"]))
I am running grinder to test a POST URI with 10 different json bodies. The response times given by grinder are not proper.Individual json body tests are giving a reasonable response time though 10 the script with with 10 different json bodies is giving a very high response time and a very low tps. I am using 1 agent with 5 worker processes and 15 threads.Can someone help me figure out where the problem might be?
The script I am using are :-
`from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from net.grinder.plugin.http import HTTPRequest
from HTTPClient import NVPair
from java.io import FileInputStream
test1 = Test(1, "Request resource")
request1 = HTTPRequest()
#response1 = HTTPResponse()
test1.record(request1)
log = grinder.logger.info
class TestRunner:
def __call__(self):
#request1.setDataFromFile("ReqBody.txt")
payload1 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req.txt")
payload2 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req2.txt")
payload3 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req3.txt")
payload4 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req4.txt")
payload5 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req5.txt")
payload6 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req6.txt")
payload7 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req7.txt")
payload8 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req8.txt")
payload9 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req9.txt")
payload10 = FileInputStream("/home/ubuntu/grinder-3.11/scripts/Req10.txt")
headersPost = [NVPair('Content-Type', ' application/json')]
#request1.setHeaders(headersPost)
#request1.setHeaders
myload = [payload1, payload2, payload3, payload4, payload5, payload6, payload7, payload8, payload9, payload10]
for f in myload:
result1 = request1.POST("http://XX.XX.XX.XX:8080/api/USblocks/ORG101/1/N/",f,headersPost)
log(result1.toString())`
First step for you is to run it with 1 thread 1 process and 1 agent . I hope it will run properly.
It looks since for loop is used all the scripts are going to run for each and every thread.
I think what you want /what should be done is that each thread should be sending one request .
You can move the request out to a global method and take some random number like Grinder.threadNo and use it to return the script to be executed . This then also demands that you remove the for loop since you can control the number of times the script is executed or leave it running for a duration .
Running 10 threads in parallel is a good number to start with then slowly you can see how many requests are actually getting accepted.
I'm working on a script to automate the running of several TestSuites across multiple projects concurrently in SoapUI 4.5.1:
import com.eviware.soapui.impl.wsdl.panels.testsuite.*;
def properties = new com.eviware.soapui.support.types.StringToObjectMap();
def currentProject = testRunner.getTestCase().testSuite.getProject();
def workspace = currentProject.getWorkspace();
def otherProject = workspace.getProjectByName('Project 1');
def otherTestSuite = CGReportsProject.getTestSuiteByName('TestSuite 1');
otherTestSuite.run(properties, true);
However, I'm also attempting to open the TestSuite Panel for each of the TestSuites that are run by the script to allow visual tracking of the Suites' progress. That's where I run into trouble:
ProWsdlTestSuitePanelBuilder.buildDesktopPanel(otherTestSuite);
This particular line throws the error:
groovy.lang.MissingMethodException: No signature of method:
static com.eviware.soapui.impl.wsdl.panels.testsuite.
ProWsdlTestSuitePanelBuilder.buildDesktopPanel() is
applicable for argument types:
(com.eviware.soapui.impl.wsdl.WsdlTestSuitePro) values:
[com.eviware.soapui.impl.wsdl.WsdlTestSuitePro#1d0b2bc6]
Possible solutions:
buildDesktopPanel(com.eviware.soapui.impl.wsdl.WsdlTestSuitePro),
buildDesktopPanel(com.eviware.soapui.model.ModelItem),
buildDesktopPanel(com.eviware.soapui.impl.wsdl.WsdlTestSuite),
buildDesktopPanel(com.eviware.soapui.model.ModelItem),
buildDesktopPanel(com.eviware.soapui.impl.wsdl.WsdlTestSuite),
buildDesktopPanel(com.eviware.soapui.model.ModelItem)
error at line: 12
Which I take to mean that the instance of the WsdlTestSuitePro I'm throwing at ProWsdlTestSuitePanelBuilder.buildDesktopPanel() isn't being accepted for some reason - but I've no idea why.
At this point, I'm also not sure if the ProWsdlTestSuitePanelBuilder.buildDesktopPanel() is really what I want anyway, but it's the only UI builder that'll take a WsdlTestSuitePro, as that apparently what all my Testsuites are.
Okay, so this falls under the newbie catagory. I wasn't paying attention to the fact that buildDesktopPanel was static.
However, I managed to work around that and create the final product:
// Create a UISupport container for all the panels we'll be showing
def UIDesktop = new com.eviware.soapui.support.UISupport();
// Basic environment information
def properties = new com.eviware.soapui.support.types.StringToObjectMap();
def currentProject = testRunner.getTestCase().testSuite.getProject();
def workspace = currentProject.getWorkspace();
// Get the various Projects we'll be using
def OtherProject = workspace.getProjectByName('Other Project');
// Get the various TestSuites we'll be running
def OtherTestSuite = OtherProject.getTestSuiteByName('Other Test Suite');
// Generate the Panels for the Testsuites
def TestSuitePanel = new com.eviware.soapui.impl.wsdl.panels.testsuite.ProWsdlTestSuiteDesktopPanel(OtherTestSuite);
// Show TestSuite Panels
UIDesktop.showDesktopPanel(TestSuitePanel);
// Run the Testsuites
OtherTestSuite.run(properties, true);