Odoo 10 - Javascript Query to a Model - odoo

I'm doing:
var callback = new $.Deferred();
new Model('pos.order').query(['invoice_id']).filter([['id', '=', '100']])
.first().then(function (order) {
if (order) {
callback.resolve(order);
} else {
callback.reject({code:400, message:'Missing Order', data:{}});
}
});
It works fine, and returns an Order object. But my issue is that i want to access the relation objects (many2many, many2one), but the order object has only the ID's of his relations. For example if i want to access the company or invoice object from the Order that i just fetched i need to do another query and i want to get all in a single query.

Use below js code to call method in py to get your required data.
new Model("pos.order")
.call("method_in_pos_order_model", [100])
.then(function (result) {
// Result is having what you want..
});
Method in Py under pos.order model
#api.model
def method_in_pos_order_model(self,id):
return self.search([('id','=',id)])
I hope this will work for you.

Related

How to get only updated row from database and make app more efficient

I'm creating laravel/vue.js CRUD app and I everything works fine for now but I'm worried about quality of my queries to database after update data.
I am using getAllData() each time when I update row in the database. Now, when I have a few records in database is not a problem to ask server each time and render new list in vue but in when I will have a few thousands of rows it will make my app slow and heavy.
Now I update database like this:
This is part of my vue.js update function:
updateStatus: function(id){
var index = _.findIndex(this.rows,["id",id]);
if (this.rows[index].pay_status=="waiting"){
axios.put("http://127.0.0.1:8000/api/payments/"+id
,{pay_status:"payed"}).then((response)=>{
this.getAllData();
}
This is my vue.js getAllData function:
getAllData: function(){
axios.get("http://127.0.0.1:8000/api/payments").then((response)=>{
this.rows = response.data;
});
}
and my PaymentsController:
namespace App\Http\Controllers;
use App\Payments;
use App\Suppliers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Faker\Generator;
class PaymentsController extends Controller
{
public function index()
{
$payments = Payments::with('suppliers')->get();
return response($payments, Response::HTTP_OK);
}
}
my updation function:
public function update(Request $request, $id)
{
$payments = new Payments();
payments::where('id', $id)->update($request->all());
}
Is thare any way to make update in more efficient way, for example get only updated row from database and put it into my existing object with rows? Or maybe i should not worried about it?
Without seeing your logic:
Your controller can return the record:
return response(['payment' => $payment], Response::HTTP_OK);
Your axios method can observe that response and then do a replace on the index (just like you did when getting the index previously)
.then((response) => {
const { payment } = response.data;
this.items[index] = payment;
})
As long as items was instantiated in data as an [] then it's observable.
If you need updated rows for particular time period.
Also, you can do one thing. When user updating the row u can store the unique ID in new table and you can fetch the data through that ID. and then you can delete that ID from new table when you don't need latest updated data.
WHILE UPDATING THE ROW via ID
insert id in new table.
update the record.
if need updated record only >> use back-end conditions as per the
requirement >> Fetch id from new table join with main table.
when you don't need that latest updated record. Delete records from
new table. >> use back-end conditions as per the requirement >>
fetch from main table.
As #Ohgodwhy said, I change my code like this and now it works fine.
update function
public function update(Request $request, $id)
{
$payments = new Payments();
payments::where('id', $id)->update($request->all());
return response(payments::where('id', $id)->get(), Response::HTTP_OK);
}
axios
updateStatus: function(id){
var index = _.findIndex(this.rows,["id",id]);
if (this.rows[index].pay_status=="oczekuje"){
axios.put("http://127.0.0.1:8000/api/payments/"+id,{pay_status:"zapłacono"}).then((response)=>{
this.rows[index].pay_status=response.data[0].pay_status;
this.waitingInvoices = this.countInvoices();
this.toPay = this.calculatePayment();
});
} else if (this.rows[index].pay_status=="zapłacono"){
axios.put("http://127.0.0.1:8000/api/payments/"+id,{pay_status:"oczekuje"}).then((response)=>{
this.rows[index].pay_status=response.data[0].pay_status;
this.waitingInvoices = this.countInvoices();
this.toPay = this.calculatePayment();
});
}
},

Yii2 REST API relational data return

I've set up Yii2 REST API with custom actions and everything is working just fine. However, what I'm trying to do is return some data from the API which would include database relations set by foreign keys. The relations are there and they are actually working correctly. Here's an example query in one of the controllers:
$result = \app\models\Person::find()->joinWith('fKCountry', true)
->where(..some condition..)->one();
Still in the controller, I can, for example, call something like this:
$result->fKCountry->name
and it would display the appropriate name as the relation is working. So far so good, but as soon as I return the result return $result; which is received from the API clients, the fkCountry is gone and I have no way to access the name mentioned above. The only thing that remains is the value of the foreign key that points to the country table.
I can provide more code and information but I think that's enough to describe the issue. How can I encode the information from the joined data in the return so that the API clients have access to it as well?
Set it up like this
public function actionYourAction() {
return new ActiveDataProvider([
'query' => Person::find()->with('fKCountry'), // and the where() part, etc.
]);
}
Make sure that in your Person model the extraFields function includes fKCountry. If you haven't implemented the extraFields function yet, add it:
public function extraFields() {
return ['fKCountry'];
}
and then when you call the url make sure you add the expand param to tell the action you want to include the fkCountry data. So something like:
/yourcontroller/your-action?expand=fKCountry
I managed to solve the above problem.
Using ActiveDataProvider, I have 3 changes in my code to make it work.
This goes to the controller:
Model::find()
->leftJoin('table_to_join', 'table1.id = table_to_join.table1_id')
->select('table1.*, table_to_join.field_name as field_alias');
In the model, I introduced a new property with the same name as the above alias:
public $field_alias;
Still in the model class, I modified the fields() method:
public function fields()
{
$fields = array_merge(parent::fields(), ['field_alias']);
return $fields;
}
This way my API provides me the data from the joined field.
use with for Eager loading
$result = \app\models\Person::find()->with('fKCountry')
->where(..some condition..)->all();
and then add the attribute 'fkCountry' to fields array
public function fields()
{
$fields= parent::fields();
$fields[]='fkCountry';
return $fields;
}
So $result now will return a json array of person, and each person will have attribute fkCountry:{...}

jQuery dataTables - Checking and adding new row if not exist using API .any()

I am trying to add new row in datatables, and by using the API .any() to check if the id is already exist in the rows and if it exist I will not add new row to my datatable, and here is the result form my request from databse see http://pastie.org/10196001 , but I am having trouble in checking.
socket.on('displayupdate',function(data){
var dataarray = JSON.parse(data);
dataarray.forEach(function(d){
if ( table.row.DT_RowId(d.DT_RowId).any() ) { // TypeError: table.row.DT_RowId is not a function
console.log('already exist cannot be added');
}else{
table.row.add(d).draw();
}
});
});
Thank you in advance.
You get the error, of course, because DT_RowId not is a function in the API. But DT_RowId is in fact the one and only property that get some special treatment from dataTables :
By assigning the ID you want to apply to each row using the property
DT_RowId of the data source object for each row, DataTables will
automatically add it for you.
So why not check rows() for that automatically injected id along with any()?
socket.on('displayupdate',function(data){
var DT_RowId,
dataarray = JSON.parse(data);
dataarray.forEach(function(d){
DT_RowId = d.DT_RowId;
if (table.rows('[id='+DT_RowId+']').any()) {
console.log('already exist cannot be added');
} else {
table.row.add(d).draw();
}
});
});
simplified demo -> http://jsfiddle.net/f1yyuz1c/

How to get Phalcon to not reload the relation each time I want to access it

I am using Phalcon and have a model Order that has a one-to-many relationship with model OrderAddress. I access those addresses through the following function:
public function getAddresses($params = null) {
return $this->getRelated("addresses", array(
"conditions" => "[OrderAddress].active = 'Y'"
));
}
The OrderAddress model has a public property errors that I do not want persisted to the database. The problem I am having is that everytime I access the getAddresses function, it reloads the object from MySQL which completely wipes the values that I set against that property.
I really only want the OrderAddress models to be loaded once, so that each call to getAddresses doesn't make another trip to the DB- it just iterates over the collection that was already loaded.
Is this possible?
I suppose there's no such option in phalcon, so it has to be implemented in your code.
You could create an additional object property for cached addresses, and return it if it's already been initialized:
protected $cachedAddresses = null;
public function getAddresses($params = null) {
if ($this->cachedAddresses === null) {
$this->cachedAddresses = $this->getRelated("addresses", array(
"conditions" => "[OrderAddress].active = 'Y'"
));
}
return $this->cachedAddresses;
}
This could be a quick solution, but it will be painful to repeat it if you have other relations in your code. So to keep it DRY, you could redefine a 'getRelated' method in base model so it would try to return cached relations, if they already were initialized.
It may look like this:
protected $cachedRelations = [];
public function getRelated($name, $params = [], $useCache = true) {
//generate unique cache object id for current arguments,
//so different 'getRelated' calls will return different results, as expected
$cacheId = md5(serialize([$name, $params]));
if (isset($this->cachedRelations[$cacheId]) && $useCache)
return $this->cachedRelations[$cacheId];
else {
$this->cachedRelations[$cacheId] = parent::getRelated($name, $params);
return $this->cachedRelations[$cacheId];
}
}
Then, you can leave 'getAddresses' method as is, and it will perform only one database query. In case you need to update cached value, pass false as a third parameter.
And, this is completely untested, but even if there're any minor errors, the general logic should be clear.

Get model with both id and query parameters

I have a route that should load a model (BatchDetail) and a number of related items (BatchItems). Since there are a great number of items I should be able to do pagination with the help of two request parameters, limit and offset.
Here is the route I set up:
App.BatchDetailRoute = Ember.Route.extend({
model: function(params) {
var store = this.get('store');
var adapter = store.get('adapter');
var id = params.batch_detail_id;
var rejectionHandler = function(reason) {
Ember.Logger.error(reason, reason.message);
throw reason
}
return adapter.ajax("/batch_details/" + id, "GET", {
data: { limit: 50, offset: 100 }
}).then(function(json) {
adapter.didFindRecord(store, App.BatchDetail, json, id);
}).then(null, rejectionHandler);
},
setupController: function(controller, model) {
return this.controllerFor('batchItems').set('model', model.get('items'));
}
})
This way, when I go to /batch_details/1 my REST adapter will fetch the correct data which I receive in json in the above code.
Now, the model hook should return a model object or a promise that can be resolved to a model object, and that's where the problem lies. In setupController (which runs after the model hook) model is set to undefined and so my code explodes.
That means that whatever adapter.ajax returns does not resolve correctly but instead returns undefined. I'm baffled, since the above mechanism is exactly how the different find methods in ember-data (findById, findByQuery, etc.) work and that's where I got my idea from.
Can you shed some light on what I'm not getting?
Thank you.