Odoo version 13: Email digests & KPI's - hash

I am trying to create a new KPI in the Digests model to show the number of new customers created per week. (Unfortunately, this functionality is not well documented).
As documented, I have created two fields in the digest model:
x_studio_kpi_new_customers (Boolean)
x_studio_kpi_new_customers_value (Integer)
The value is
for record in self:
start, end, company = record._get_kpi_compute_parameters()
record.x_studio_kpi_new_customers_value = sum(self.env['res.partner'].search([
('x_studio_when', '>=', start),
('x_studio_when', '<', end)
]).mapped('x_studio_counter'))
x_studio_counter is just the value 1 in all records
x_studio_when is the record creation date (have also tried with a datetime field)
I have also tried the code below:
for record in self:
start, end, company = record._get_kpi_compute_parameters()
new_customers = self.env['res.partner'].search_count([('x_studio_when', '>=', start), ('x_studio_when', '<', end)])
record['x_studio_kpi_new_customers_value'] = new_customers
I keep getting 0.
Any help will be appreciated.

In order to build your customized digest, follow these steps:
You may want to add new computed fields with Odoo Studio:
You must create 2 fields on the digest object:
first create a boolean field called kpi_myfield and display it in the KPI's tab;
then create a computed field called kpi_myfield_value that will compute your customized KPI.
Create below "compute_kpis_actions" method and after that digest mail able to view count.
def compute_kpis_actions(self, company, user):
res = super(Digest, self).compute_kpis_actions(company, user)
res['x_studio_kpi_new_customers'] = 'your_module_name.your_action_name&menu_id=%s' % self.env.ref(your_module_name.your_menu_name').id
return res

Related

Creating a LocalTime BsonDatetime object

I have a large logging and data entry program that receives DataTable object with 1 DataRow. The DataTable have random amount of columns, with random column name and type so i cannot have class for each. Using these DataColumn i get the DataType and build a BsonDocument from scratch out of this.
Here's a short example
public void ParseData(DataTable table)
{
// create the document
var document = new BsonDocument();
// get the only row in the table
var row = table.Rows[0];
// for each column we add the property
foreach (DataColumn column in table.Columns)
{
// create an empty value
BsonValue value = null;
// current column value
var columnValue = row[column.ColumnName];
// set the value based on the datatype
if (column.DataType == typeof(string)) value = new BsonString(columnValue.ToString());
else if (column.DataType == typeof(int)) value = new BsonInt32(Convert.ToInt32(columnValue));
else if (column.DataType == typeof(float)) value = new BsonDouble(Convert.ToDouble(columnValue));
else if (column.DataType == typeof(double)) value = new BsonDouble(Convert.ToDouble(columnValue));
else if (column.DataType == typeof(bool)) value = new BsonBoolean(Convert.ToBoolean(columnValue));
else if (column.DataType == typeof(DateTime)) value = new BsonDateTime(Convert.ToDateTime(columnValue));
// add the element
document.Add(new BsonElement(column.ColumnName, value));
}
// insert the document in the generic collection
InsertDocument(document);
}
As you can see it's pretty simple. I have removed a lot of types in the list as we have many custom types that might pass so i just kept the basic ones. The problem is that i cannot figure out how to force the BsonDateTime to save as local time in the collection. When doing filters with legacy apps it's not working. I need them to be saved as local time. It's never been an issue in the past but because of those legacy apps from the early 90's that still need support i have to figure something out.
I also need to reload them as local time. If i could, i would save them as string but i can't because since all columns are random i do not know when loading if a specific BsonString is really a string or if it's a DateTime. For reloading i must not reload really as local time. I must reload the exact value in the database. I only control the creation of the document. But reading i only control a few one's that will be reading from it that are in C#, Java and C++. The rest are legacy apps that companies doesn't even exist anymore.
I did try to just modify every single date that came in the system to account for UTC and change the date to when saved as UTC it's stored property and filters from legacy apps still works but all of .NET, Java and C++ apps load up the wrong value and not the written value.
Is there a way to just disable UTC in a specific collection or database in MongoDB directly like you can in SQL server ?
MongoDB stores times in UTC and does not have time zone support. You can store any values you like but they will be interpreted as UTC timestamps by most MongoDB-related software.

Adding columns to a Web2py table in a form

In my web2py application, in the controller I read from an external DB the names of students I want to take a register for. I loop through the resulting list adding the list elements to a new list.
for student in pupils_query:
attendance_list.insert(counter, [student[0], student[1], student[2], student[3]])
counter += 1
counter = 0
Then for each student I read their attendance codes for the day so far from another table, and append them to attendance_list:
for attendance_code in attendance_result:
attendance_list[counter].append(attendance_code)
Now, I'm going to want to make a form from all this, using a table which will show each students' attendance code in a text input (so they can be updated if wrong), then have a dropdown for input of the current lesson code.
I'm using a FORM and TABLE helper to create the table in the form:
form=FORM(TABLE(*[TR(*rows) for rows in attendance_list]))
but can't seem to be able to add a new 'row' form item with something like:
select = "SELECT("+ main_reg_list +")"
attendance_list[counter].append(select)
where main_reg_list is dictionary of acceptable attendance codes (or of course, any other form input element).
In summary, I'm stuck adding new TDs to a table made with a TABLE helper from a list of lists. I bet I'm not the first person to overcome this problem.
I am still not clear about what you want. I think you want table of student information and in one column you want dropdown. Something similat to following image
Above form is created from following code.
I hope following code will help you:
# controller/default.py
def index():
# Dummy attendance list, list after appending attendance code
attendance_list = [['stud_id_1', 'first_name_1', 'last_name_1', 'attendance_code_1'],
['stud_id_2', 'first_name_2', 'last_name_2', 'attendance_code_2'],
['stud_id_3', 'first_name_3', 'last_name_3', 'attendance_code_5'],
['stud_id_4', 'first_name_4', 'last_name_4', 'attendance_code_4']]
possible_att_code = ['attendance_code_1', 'attendance_code_2', 'attendance_code_3', 'attendance_code_4', 'attendance_code_5']
# initialise form_rows with Table heading
form_rows = [THEAD(TR(TH('ID'), TH('First Name'), TH('Last Name'), TH('Attendence Code')))]
for attendance in attendance_list:
attendance_code_dropdown = _get_dropdown(attendance[0], attendance[3], possible_att_code)
td_list = [TD(attendance[0]), TD(attendance[1]), TD(attendance[2]),
TD(attendance_code_dropdown)]
table_row = TR(td_list, _id='row_' + attendance[0])
form_rows.append(table_row)
# Form submit button
form_rows.append(TR(INPUT(_type='submit')))
form = FORM(TABLE(*form_rows), _name='student_attendance',
_id='student_attendance')
if form.accepts(request, session):
# Write code to update record
pass
return dict(form=form)
def _get_dropdown(stud_id, att_code, possible_att_code):
option_list = []
for pac in possible_att_code:
if pac == att_code:
option_list.append(OPTION(pac, _value=pac, _selected='selected'))
else:
option_list.append(OPTION(pac, _value=pac))
return SELECT(*option_list, _name=stud_id)
<!-- views/default/index.html -->
{{extend 'layout.html'}}
{{=form}}
Are my assumptions correct? or you want any thing else? Comment if didn't understood code.

How to read UnitPrice from invoice line in QBO API v3 .NET

The bizarre properties in the .NET SDK continue to baffle me. How do I read the UnitPrice from an invoice line?
If I do this:
sild = (SalesItemLineDetail)line.AnyIntuitObject;
ln = new QBInvoiceLine(); // My internal line item class
ln.Description = line.Description;
ln.ItemRef = new QBRef() { Id = sild.ItemRef.Value, Name = sild.ItemRef.name };
if (sild.QtySpecified)
ln.Quantity = sild.Qty;
else
ln.Quantity = 0;
if (sild.ItemElementName == ItemChoiceType.UnitPrice)
ln.Rate = (decimal)sild.AnyIntuitObject; // Exception thrown here
The last line throws an invalid cast exception, even though the debugger shows that the value is 20. I've tried other types but get the same exception no matter what I do. So I finally punted and am calculating the rate like so:
ln.Rate = line.Amount / ln.Quantity;
(With proper rounding and checking for divide by zero, of course)
While we're on the subject... I noticed that in many cases ItemElementName == ItemChoiceType.PriceLevelRef. What's up with that? As far as I know, QBO doesn't support price levels, and I certainly wasn't using a price level with this invoice or customer. In this case I was also able to get what I needed from the Amount property.
Try this-
SalesItemLineDetail a1 = (SalesItemLineDetail)invoice11.Line[0].AnyIntuitObject;
object unitprice = a1.AnyIntuitObject;
decimal quantity = a1.Qty;
PriceLevelRef as an 'entity' is not supported. This means CRUD operations are not supported on this entity.
The service might however be returning readonly values in the transactions sometimes, but since this not mentioned in the docs, please consider it as unsupported.
Check that both request/response are in either json or xml format-
You can use the following code to set that-
ServiceContext context = new ServiceContext(appToken, realmId, intuitServiceType, reqvalidator);
context.IppConfiguration.Message.Request.SerializationFormat = Intuit.Ipp.Core.Configuration.SerializationFormat.Json;
context.IppConfiguration.Message.Response.SerializationFormat = Intuit.Ipp.Core.Configuration.SerializationFormat.Json;
Also, in QBO UI, check if Company->sales settings has Track Quantity and Price/rate turned on.

Form Gathering Info from Two Other Forms

I have a form that creates a New Work Order. I want to be able to pull the ClientID from the New Client Form or the Main Menu, whichever is open. However I am not getting the desired results:
I have used =IIf(IsNull(Forms![New Client]![txtClientID]), Forms![Main Menu]![txtClientID], Forms![New Client]![txtClientID]) in the Default Value of the Control on the New Work Order Form. I get the correct ID when I go to the form from New Client, but a #Name error when I try to access it from the Main Menu.
What can I do to make it work?
You need to check if the form is loaded, for example (you need to add your own error traps):
Function IsLoaded(ByVal strFormName As String) As Boolean
Const conObjStateClosed = 0
Const conDesignView = 0
If SysCmd(acSysCmdGetObjectState, acForm, strFormName) <> conObjStateClosed Then
If Forms(strFormName).CurrentView <> conDesignView Then
IsLoaded = True
End If
End If
However, it may be easier to use OpenArgs ( http://msdn.microsoft.com/en-us/library/office/ff820845(v=office.15).aspx )
In which case you could say something like:
If IsNull(Me.OpenArgs) Then
MsgBox "No openargs"
Else
Me.txtClientID = Me.Openargs
End If
Or even use Openargs to set the default value.

How do i get the primary id (pid) for a document in CM8.4 using the Item ID and Component ID?

Im using IBM Content Manager 8.4.1 and I need to write some code to retreive documents. The information I have is the Item ID and Component ID which im retreiving from the document views under the ICMADMIN (Default) Schema.
The below block gives a sample using DKPidICM object to generate the primary id (pid) used to get a workpackage but I want to get a document instead and need to know what is different.
DKPidICM pidicm = new DKPidICM();
pidicm.setComponentId(compId);
pidicm.setItemId(itemId);
pidicm.setDatastoreName(datastoreName);
pidicm.setComponentTypeId("204");
pidicm.setVersionNumber("1");
pidicm.setObjectType("WORKPACKAGE");
pidicm.setDatastoreType("ICM");
pidicm.getPrimaryId();
To retreive a document what do i need to set for
Component Type ID
Object Type
Or is there a better way all together
It turns out that the component type id is based directly on the item type you are looking for so the Name from the system adminstration client under the item.
The most straight foward way I found to determine the componentTypeId was to:
1).query for that item type queryService.setQueryString(**"/itemTypeName"**, CMBBaseConstant.CMB_QS_TYPE_XPATH);
2).Create the corresponding DKPidICM DKPidICM pidicm = new DKPidICM(pidString)
3).Get the componentID from that pidicm.getComponentTypeId()
More complete Sample below
CMBQueryService queryService = cmbConnection.getQueryService();
queryService.setAsynchSearch(false); // synchronous search
queryService.setMaxResults(1);
queryService.setQueryString("/itemTypeName", CMBBaseConstant.CMB_QS_TYPE_XPATH);
queryService.runQuery();
CMBResultData results = (CMBResultData) queryService.getResults();
CMBSearchResults searchResults = new CMBSearchResults();
searchResults.setConnection(cmbConnection);
searchResults.newResults(results);
if (searchResults.getCount() > 0) {
String pidString = searchResults.getItem(0).getPidString();
DKPidICM pidicm = new DKPidICM(pidString);
return pidicm.getComponentTypeId();