Append all stock.move ID's to list from all chain of related records - odoo

I have records in the stock.move table that has One2many relation to stock.move.reconcile with column move_to_id which is the ID of another record in stock.move table. So this chain can be thousands of records.
As you can see in my example I loop trough all records and go down tier by tier, but as I said before there could be thousands of linked records so my approach will not work here.
I do know that probably I need to use a while loop here, something like while there is move_to_ids, then I should loop through records and keep adding IDs to list, but I just can't figure it out how to do it.
move1(stock.move ID = 10) record that has One2many relation with 2 records inside: move_to_ids (stock.move.reconcile)
each of move_to_ids has move_to_id(many2one, 'stock.move' ID = 11)
each of this move_to_id(stock.move, ID=11) records have again any number of move_to_ids (stock.move.reconcile) and each of thismove_to_idsrecords havemove_to_id('stock.move', ID=12)` and so on.
So basically I want to add to list all move_to_id IDs 10, 11, 12, etc. to list for all related move_to_ids.
moves_to_recalculate = [10,11,12] and so on until when there is 0 move_to_ids to get move_to_id from.
class StockMove(models.Model):
_name = 'stock.move'
move_to_ids = fields.One2many(
'stock.move.reconcile', 'move_from_id', string='Move to')
move_from_ids = fields.One2many(
'stock.move.reconcile', 'move_to_id', string='Move From'
)
class StockMoveReconcile(models.Model):
_name = 'stock.move.reconcile'
_description = 'Stock Move Reconcile'
move_to_id = fields.Many2one('stock.move', string='Move To')
move_from_id = fields.Many2one('stock.move', string='Move From')
def recalculate(self):
moves = self.browse(('active_ids'))
moves_to_recalculate = []
for move1 in moves:
#I add my first move in chain to list
moves_to_recalculate.append(move1.id)
#First move have 2 moves_to_ids so i make another loop to add it ID to list
for second_tier_move in move.move_to_ids:
moves_to_recalculate.appen(second_tier_move.move_to_id.id)
# secont tier move has 1 move_to_ids so i do another loop, and add it's ID to list.
for third_tier_move in second_tier_move.move_to_ids:
moves_to_recalculate.appen(third_tier_move.move_to_id.id)
#third_tier_move has another move_to_ids , and so on.

I got answer from other resource but I think i need to post it here because the answer is excellent.
def recalculate_fifo(self):
moves = self.browse(self._context.get('active_ids'))
moves_to_recalculate = moves
current_moves = moves
while current_moves:
current_moves = current_moves.mapped('move_to_ids.move_to_id')
current_moves -= moves_to_recalculate
moves_to_recalculate |= current_moves

Related

How to add widget to entire column in a QTableWidget?

New to PyQt5. I'm trying to create a Table using QTableWidget where certain columns are spin box or drop down widgets. I am able to add create a widget and it to a particular cell. I have the following questions:
How do I automatically add these widgets when a user add a new row to a table? From reading the documentation, it seems I can use itemDelegateForRow, but I'm not sure which methods to implement from the QAbstractItemDelegate class. Can someone point me to a small example on how to use this?
The column Parent is a combo box whose values need to get updated with a list of all other values in column Block. By default, it has a single item 'top'. When a row is added with say, Block=A, then in the 2nd row the list of valid choices for Parent shoudl be A, top, etc. What signal should I monitor/connect to update the combox box and how?
Right now, I have the following code to create a 5x5 table.
hier_blocks = QTableWidget(5, 5)
hier_blocks.verticalHeader().setDefaultSectionSize(25)
hdrs = ['Block', 'Parent', 'Library', 'Freq (MHz)', 'Qty']
hier_blocks.setHorizontalHeaderLabels(hdrs)
parent_box = QComboBox(hier_blocks)
parent_box.addItem('top')
hier_blocks.setCellWidget(0, 1, parent_box)
lib_box = QComboBox(hier_blocks)
hier_blocks.setCellWidget(0, 2, lib_box)
freq_box = QSpinBox(hier_blocks)
freq_box.setRange(1, 4000)
hier_blocks.setCellWidget(0, 3, freq_box)
qty_box = QSpinBox(hier_blocks)
qty_box.setRange(1, 20)
hier_blocks.setCellWidget(0, 4, qty_box)
hier_layout = QVBoxLayout()
hier_layout.addWidget(hier_blocks)

Arcpy Script to loop through field and run Union Analysis

I have a polygon file in form of a fishnet. Also another feature class with polygons named Trawl_Buffers. There is a unique field within Trawl_Buffers based on YEAR. I'd like to create a script to run a selection on YEAR, and then perform a union analysis with the fishnet polygon for each YEAR. So the desired output would be "Trawl_Buffers_union2003", "Trawl_Buffers_union2004" etc. I have a function that will get me the unique list of the years, and puts them in a list which i called vals.
Then seems I need to run a for loop over this list of unique years, create a temporary selection, then use that as input for the union, but I am having trouble implementing the query process.
Here is where I started, but seriously tripping
import arcpy
#Set the data environment
arcpy.env.overwriteOutput = True
arcpy.env.workspace = r'C:\Data\working\AK_Fishing_VMS\2021_Delivery\ArcPro_proj\ArcPro_proj.gdb'
trawlBuffs = r'C:\Data\working\AK_Fishing_VMS\2021_Delivery\ArcPro_proj\ArcPro_proj.gdb\buffers\buffers_testing'
fishnet = r'C:\Data\working\AK_Fishing_VMS\2021_Delivery\ArcPro_proj\ArcPro_proj.gdb\fishnets\vms_net1k'
unionOut = r'C:\Data\working\AK_Fishing_VMS\2021_Delivery\ArcPro_proj\ArcPro_proj.gdb\unions\union'
# function to get unique values for the YEAR field found within the trawlBuffs fc
def unique_values(table, field):
with arcpy.da.SearchCursor(table, [field]) as cursor:
return sorted({row[0] for row in cursor})
# Get the unique values for the field 'YEAR' found within the 'trawl_buffs' featureclass table
vals = unique_values(trawlBuffs, "YEAR")
# Create a query string for the selected country
yearSelectionClause = '"YEAR" = ' + "'" + vals + "'"
#loop through the years, create selection, union, make permanent
for year in vals:
year_layer = str(year) + "_union"
arcpy.MakeFeatureLayer_management(trawlBuffs, year_layer)
arcpy.SelectLayerByAttribute_management(year_layer, "NEW_SELECTION", "\"YEAR"\" = %d" % (year))
arcpy.Union_analysis(fishnet, year_layer , unionOut)
arcpy.CopyFeatures_management(year_layer, "union_" + str(year))

Key-value pairs in SQL table

I am building a Django app and I would like to show some statistics on the main page, like total number of transactions, percentage of successful transactions, daily number of active users etc.
I don't want to calculate these values in the view every time a user requests the main page for performance reasons. I thought of 2 possible solutions.
(1) Create a number of one-record tables
Create a table for each of the statistics, e.g.:
from django.db import models
class LastSuccessfulTransactionDate(models.Model):
date = models.DateTimeField()
class TotalTransactionAmount(models.Model):
total_amount = models.DecimalField(max_digits=8, decimal_places=2)
# ...
and make sure that only one record exists in each table.
(2) Create a table with key-value data
class Statistics(models.Model):
key = models.CharField(max_length=100)
value = models.TextField()
and save the data by doing:
from datetime import datetime
from decimal import Decimal
import pickle
statistics = {
'last_successful_transaction_date': datetime(2010, 2, 3),
'total_transaction_amount': Decimal('1234.56'),
}
for k, v in statistics.items():
try:
s = Statistics.objects.get(key=k)
except Statistics.DoesNotExist:
s = Statistics(key=k)
s.value = base64.b64encode(pickle.dumps(v, pickle.HIGHEST_PROTOCOL)).decode()
s.save()
and retrieve by:
for s in Statistics.objects.all():
k = s.key
v = pickle.loads(base64.b64decode(s.value.encode()))
print(k, v)
In both cases the data would be updated every now and then by a cron job (they don't have to be very acurate).
To me solution (2) looks better, because to display the main page I would need to get data from the Statistics table only, not from a number of one-record tables. Is there any recommended solution to this problem? Thanks
There is even better solution if you are using Postgresql, which is JSONField. You can directly store the key value pair in the JSONField. Try like this:
# model
class Statistics(models.Model):
records = JSONField()
# usage
statistics = {
'last_successful_transaction_date': datetime(2010, 2, 3),
'total_transaction_amount': Decimal('1234.56'),
}
Statistics.objects.create(records=statistics)
Statistics.objects.filter(records__last_successful_transaction_date= datetime(2010, 2, 3)) # Running query
s = Statistics.objects.filter(records__last_successful_transaction_date= datetime(2010, 2, 3)).first()
new_statistics = {
'last_successful_transaction_date': datetime(2012, 2, 3),
'total_transaction_amount': Decimal('1234.50'),
}
records = s.records
records.update(new_statistics)
s.records = records
s.save()

Is it possible to compute many2many field values without storing them?

I want to create a virtual Many2many field for informational purpose only. Is it possible to compute and populate Many2many field without storing the generated virtual records?
Yes, It is possible to create Virtual Many2many field for informational purpose. Please see the below sample code,
#api.one
#api.depends(
'move_id.line_id.account_id',
'move_id.line_id.reconcile_id.line_id',
'move_id.line_id.reconcile_partial_id.line_partial_ids',
)
def _compute_move_lines(self):
# Give Journal Items related to the payment reconciled to this invoice.
# Return partial and total payments related to the selected invoice.
self.move_lines = self.env['account.move.line']
if not self.move_id:
return
data_lines = self.move_id.line_id.filtered(lambda l: l.account_id == self.account_id)
partial_lines = self.env['account.move.line']
for data_line in data_lines:
if data_line.reconcile_id:
lines = data_line.reconcile_id.line_id
elif data_line.reconcile_partial_id:
lines = data_line.reconcile_partial_id.line_partial_ids
else:
lines = self.env['account.move.line']
partial_lines += data_line
self.move_lines = lines - partial_lines
move_lines = fields.Many2many('account.move.line', string='Entry Lines',
compute='_compute_move_lines')
You can see above example in /addons/account/account_invoice.py file in the odoo addons.

Name a Table with a Variable in LUA (LÖVE Engine)?

Basically:
I am making a game in the LÖVE Engine where you click to create blocks
Every time you click, a block gets created at your Mouse X and Mouse Y
But, I can only get one block to appear, because I have to name that block (or table) 'object1'
Is there any way to create table after table with increasing values? (like object1{}, object2{}, object3{}, etc... But within the main table, 'created_objects')
But only when clicked, which I suppose rules out the looping part (but if it doesn't please tell me)
Here's my code so far, but it doesn't compile.
function object_create(x, y, id) **--Agruments telling the function where the box should spawn and what the ID of the box is (variable 'obj_count' which increases every time a box is spawned)**
currobj = "obj" .. id **--Gives my currently created object a name**
crob.[currobj] = {} **--Is supposed to create a table for the current object, which holds all of its properties. **
crob.[currobj].body = love.physics.newBody(world, x, y, "dynamic")
crob.[currobj].shape = love.physics.newRectangleShape(30, 30)
crob.[currobj].fixture = love.physics.newFixture(crob.[currobj].body, crob.[currobj].shape, 1) **--The properties**
crob.[currobj].fixture:setRestitution(0.3)
But what should I replace [currobj] with?
Solved
Found what I was looking for. Here's the code if people are wondering:
function block_create(x, y, id) --(the mouse x and y, and the variable that increases)
blocks[id] = {}
blocks[id][1] = love.physics.newBody(world, x, y, "dynamic")
blocks[id][2] = love.physics.newRectangleShape(45, 45)
blocks[id][3] = love.physics.newFixture(blocks[id][1], blocks[id][2])
blocks[id][3]:setRestitution(0.2)
blocks[id][4] = math.random(0, 255) --The Color
blocks[id][5] = math.random(0, 255)
blocks[id][6] = math.random(0, 255)
blockcount = blockcount + 1
i would probably do something like this.
local blocks = {} -- equivalent of your crob table
function create_block(x, y)
local block = funcToCreateBlock() -- whatever code to create the block
table.insert(blocks, block)
return block
end
if you wanted to get a reference to the block you just created with the function, just capture it.
-- gives you the new block, automatically adds it to the list of created blocks
local new_block = create_block(0, 10)
that sticks block objects in your block table and automatically gives each one a numeric index in the table. so if you called create_block() 3 times for 3 different mouse clicks, the blocks table would look like this:
blocks = {
[1] = blockobj1,
[2] = blockobj2,
[3] = blockobj3
}
you could get the second block obj from the blocks table by doing
local block2 = blocks[2]
or you could loop over all the blocks in the table using pairs or ipairs
for idx, block in pairs(blocks) do
-- do something with each block
end
sorry if this doesn't exactly answer your question. but from what you wrote, there didn't seem to be a real reason why you'd need to name the blocks anything specific in the crob table.
If you want those tables to be global, then you can do something like:
sNameOfTable = "NAME"
_G[sNameOfTable] = {1,2}
and then you will have a table variable NAME as depicted here (Codepad).
Otherwise, if you want it to be a child to some other table, something like this would also do:
tTbl = {}
for i = 1, 20 do
local sName = string.format( "NAME%02d", i )
tTbl[sName] = {1,2}
end
for i, v in pairs(tTbl) do
print( i, v )
end
Don't worry about the unsorted output here(Codepad). Lua tables with indexes need not be sorted to be used.