Odoo 13 - Modify Journal Items when create Bill Vendor - odoo-13

I have question about Vendor Bill.
When we create vendor bill, there is a journal items tab that the data will be generated when we choose Receipts.
I have requirement that user want to reformat the journal item, let say to add 1 account item of debit and credit.
Im looking the sourcode, and the journal items generated from this line :
moves_lines = self.env['stock.move'].browse([rec.id for rec in picking_ids.move_ids_without_package])
new_lines = self.env['account.move.line']
for line in moves_lines:
new_line = new_lines.new(line._prepare_picking_account_move_line(self))
# if i comment the above line, the journal items will not generate
new_line.account_id = new_line._get_computed_account()
new_line.stock_move_id = line.id
new_line._onchange_price_subtotal()
new_lines += new_line
My questions are :
How can i modify the journal items account format ?
If i comment the new_lines.new() it will not generate the journal items. But i don't know how to modify the journal items generation.
For information the code is created by previous programmer but currently its not possible to contact them.
Thank you before

According to your piece of code, you "just" need to create a new account move line and add it to your record set (new_lines).
You will probably have to do it this way:
moves_lines = self.env['stock.move'].browse([rec.id for rec in picking_ids.move_ids_without_package])
new_lines = self.env['account.move.line']
for line in moves_lines:
new_line = new_lines.new(line._prepare_picking_account_move_line(self))
# if i comment the above line, the journal items will not generate
new_line.account_id = new_line._get_computed_account()
new_line.stock_move_id = line.id
new_line._onchange_price_subtotal()
new_lines += new_line
# do your computation stuff here
dict_of_values = {
debit: DEBIT_VALUE,
credit: CREDIT_VALUE,
account: ACCOUNT_ID,
**any_other_required_values
}
new_account_move_line = self.env['account.move.line'].new(dict_of_values)
new_lines += new_account_move_line
Another way of doing that is to gather account_move_lines you want to create and to write them directly on your account_move.
amls_to_write = []
amls_to_write += [(0, 0, aml_dict_of_values)]
your_account_move.write({'line_ids': amls_to_write})
regarding the "cryptic" (0, 0, values), it corresponds to that:
(ORM_METHOD_NUMBER, ID_OF_RECORD, VALUES_OF_RECORD)
I let you have a look at the ORM methods: (don't forget to change the link for the version you are developing in)
https://www.odoo.com/documentation/14.0/developer/reference/addons/orm.html#common-orm-methods
Note that the AccountMove model has a lot of constraint and that you have to balance the account_move_line together for the global balance of the account_move to be 0. (basic accounting stuff)
By the way, the variable names are highly unclear and there are rooms for confusion here. You should rename those to match what they are.
moves_lines and line are stock_move -> stock_moves and stock_move
new_lines and new_line are account_move_line -> account_move_lines and account_move_line (or aml if it's too long)

Related

Merge every x element in multiple lists to return new list

I'm writing a script that scrapes all of the data from my works ticketing site and the end goal is to have it send a text when a new ticket enters the bucket with all of the important info of the ticket.
Python 3.10
So far, it pulls from a scattered list and combines all of the elements into an appropriate group ie. ticket numbers,titles and priorities.
tn = rawTickets[0::14]
title = rawTickets[5::14]
priority = rawTickets[9::14]
With this I can say
num = x
wholeticket = tn[num], title[num], priority[num],
print(wholeticket)
and get x ticket in the list
# Results: "tn0, title0, priority0"
I want it to print all of the available tickets in the list based on a range
totaltickets = 0
for lines in rawTickets:
if lines == '':
totaltickets += 1
numrange = range(totaltickets)
so lets say there are only 3 tickets in the queue,
I want it to print
tn0, title0, priority0,
tn1, title1, priority1,
tn2, title2, priority2,
But I want to avoid doing this;
ticket1 = tn[0], title[0], priority[0],
ticket2 = tn[1], title[1], priority[1],
ticket3 = tn[2], title[2], priority[2],
flowchart to help explain
You could use zip:
tickets = list(zip(rawTickets[0::14], rawTickets[5::14], rawTickets[9::14]))
This will give you a list of 3-tuples.
You could do something like that:
l1 = [*range(0,5)]
l2 = [*range(5,10)]
l3 = [*range(10,15)]
all_lst = [(l1[i], l2[i], l3[i]) for i in range(len(l1))]
Or you could use zip as trincot offered.
Note that on large scales, zip is much faster.

How do I count multiple lines in a list?

I'm a very new Python user. My project is to take a very long (20k lines) file that includes movies and actors in them and refine it. I'm trying to find out which of the movies listed has the highest number of actors.
I'm not sure how to do multiple counts of a single file.
This is the file that starts the project. It repeats like that with different movie titles for 20k lines. Pic of original file The first part of the project is to build a list which contains every movie's full cast list which is what the code below does. Now what I'm trying to do is get the program to count how many actors is in each movie and print which one has the highest number of actors.
lines_seen = list()
fhand = open...
#opens but I don't want to show address
actors = list()
titles = list()
is_Actor = True
for line in fhand:
line = line.rstrip()
if (is_Actor):
titles.append(line)
if line not in lines_seen:
lines_seen.append("The title of the movie is:")
lines_seen.append(line)
print(" ")
print("The title of the movie is '", line, "'")
print("The actors in the movie are:")
elif not (is_Actor):
lines_seen.append(line)
print(line)
actors.append(line)
is_Actor = not(is_Actor)
fhand.close()
Heres what I've done so far
actors = dict()
is_Title = True
for line in fhand:
words = line.split()
if (is_Title):
if line not in actors:
actors[line] = 1
else:
actors[line] = actors[line] + 1
is_Title = not is_Title
Now I'm trying to get it to return the highest value. I've googled it and it tells me to use max() but that returns a value of 97 when I know the highest value is 207. What do I do from here?
Recommendation #1: Make yourself a small chunk of data that you can experiment with and read/print results. It will be 55x (my estimate) easier to troubleshoot than 20k lines. Maybe 2 movies, 1 with 2 actors, 1 with 1 actor.
Are you familiar with python dictionaries? It seems what you want to do is associate a list of actors with a movie title. Then you can inspect the sizes of the lists in the dictionary to find the one with the highest length.
In basic Python, you should ...
make an empty dictionary outside of your loop to hold the results, as you are doing with actors, etc.
start reading the file. It seems like your data is in a predictable pattern that the title is followed by a single actor name, so if you want to keep your current reading construct (an alternate would be to read 2 lines each pass through a different loop) you need to "hold onto the movie title" until the next loop to get the actor, so in pseudocode you could modify your loop to something like:
title = None
is_actor = False
for line in fhand:
if not is_actor: # you have a title...
title = line
else: # you have an actor
# get the list from the dictionary for the current title, or make a new list if no entry yet
# add the actor to the list
# put the list back into the dictionary
is_actor = not is_actor
Then inspect your dictionary and manipulate it as needed
For a primer on dictionaries (and other introductory concepts) I strongly recommend Think Python. See the whole chapter on dictionaries.

extract just one element from list and write it into a csv as another name

I have a list:
IDs = ["111111111111", "222222222222"]
and create a csv with this code:
for acc in IDs:
with open("/tmp/test.csv", "a+") as f:
test = csv.writer(f)
test.writerow([IDs])
result is:
{'111111111111', '222222222222'}
what i want to do is like:
if IDs == "111111111111":
IDs = "AccountA"
elif IDs == "222222222222":
IDs = "AccountB"
expected result in csv:
Account A
some information about account a i put later on it
Account B
some information about account a i put later on it
How can I achieve the result?
You could use a dictionary. What you do is you create a dictonary with all data. At the left side you would have your input, and and the right side you have your data that your want to write. For this case, take a look at this dictionary:
data = {
'111111111111':'AccountA',
'222222222222':'AccountB'
}
Than, create a loop around your list and create a new list, with the new ids, configured with your data.
new_ids = []
for x in ids:
new_ids.append(data[x])
Now, you can use the new_ids list to use in your write function.
Hope it helps.
Sincerly, Chris Fowl.

Convert everything in a dictionary to lower case, then filter on it?

import pandas as pd
import nltk
import os
directory = os.listdir(r"C:\...")
x = []
num = 0
for i in directory:
x.append(pd.read_fwf("C:\\..." + i))
x[num] = x[num].to_string()
So, once I have a dictionary x = [ ] populated by the read_fwf for each file in my directory:
I want to know how to make it so every single character is lowercase. I am having trouble understanding the syntax and how it is applied to a dictionary.
I want to define a filter that I can use to count for a list of words in this newly defined dictionary, e.g.,
list = [bus, car, train, aeroplane, tram, ...]
Edit: Quick unrelated question:
Is pd_read_fwf the best way to read .txt files? If not, what else could I use?
Any help is very much appreciated. Thanks
Edit 2: Sample data and output that I want:
Sample:
The Horncastle boar's head is an early seventh-century Anglo-Saxon
ornament depicting a boar that probably was once part of the crest of
a helmet. It was discovered in 2002 by a metal detectorist searching
in the town of Horncastle, Lincolnshire. It was reported as found
treasure and acquired for £15,000 by the City and County Museum, where
it is on permanent display.
Required output - changes everything in uppercase to lowercase:
the horncastle boar's head is an early seventh-century anglo-saxon
ornament depicting a boar that probably was once part of the crest of
a helmet. it was discovered in 2002 by a metal detectorist searching
in the town of horncastle, lincolnshire. it was reported as found
treasure and acquired for £15,000 by the city and county museum, where
it is on permanent display.
You shouldn't need to use pandas or dictionaries at all. Just use Python's built-in open() function:
# Open a file in read mode with a context manager
with open(r'C:\path\to\you\file.txt', 'r') as file:
# Read the file into a string
text = file.read()
# Use the string's lower() method to make everything lowercase
text = text.lower()
print(text)
# Split text by whitespace into list of words
word_list = text.split()
# Get the number of elements in the list (the word count)
word_count = len(word_list)
print(word_count)
If you want, you can do it in the reverse order:
# Open a file in read mode with a context manager
with open(r'C:\path\to\you\file.txt', 'r') as file:
# Read the file into a string
text = file.read()
# Split text by whitespace into list of words
word_list = text.split()
# Use list comprehension to create a new list with the lower() method applied to each word.
lowercase_word_list = [word.lower() for word in word_list]
print(word_list)
Using a context manager for this is good since it automatically closes the file for you as soon as it goes out of scope (de-tabbed from with statement block). Otherwise you would have to use file.open() and file.read().
I think there are some other benefits to using context managers, but someone please correct me if I'm wrong.
I think what you are looking for is dictionary comprehension:
# Python 3
new_dict = {key: val.lower() for key, val in old_dict.items()}
# Python 2
new_dict = {key: val.lower() for key, val in old_dict.iteritems()}
items()/iteritems() gives you a list of tuples of the (keys, values) represented in the dictionary (e.g. [('somekey', 'SomeValue'), ('somekey2', 'SomeValue2')])
The comprehension iterates over each of these pairs, creating a new dictionary in the process. In the key: val.lower() section, you can do whatever manipulation you want to create the new dictionary.

Search the nth number of string in side the another list in python

add name, where is a string denoting a contact name. This must store as a new contact in the application.
find partial, where is a string denoting a partial name to search the application for. It must count the number of contacts starting with and print the count on a new line.
Given sequential add and find operations, perform each operation in order.
Input:
4
add hack
add hackerrank
find hac
find hak
Sample Output
2
0
We perform the following sequence of operations:
1.Add a contact named hack.
2.Add a contact named hackerrank.
3.Find and print the number of contact names beginning with hac.
There are currently two contact names in the application
and both of them start with hac, so we print 2 on a new line.
4.Find and print the number of contact names beginning with hak.
There are currently two contact names in the application
but neither of them start with hak, so we print 0 on a new line.
i solved it but it is taking long time for large number of string. my code is
addlist =[]
findlist=[]
n = int(input().strip())
for a0 in range(n):
op, contact = input().strip().split(' ')
if(op=='add'):
addlist.append(contact)
else:
findlist.append(contact)
for item in findlist:
count=0
count=[count+1 for item2 in addlist if item in item2 if item==item2[0:len(item)]]
print(sum(count))
is there any other way to avoid the long time to computation.
As far as optimizing goes I broke your code apart a bit for readability and removed a redundant if statement. I'm not sure if its possible to optimize any further.
addlist =[]
findlist=[]
n = int(input().strip())
for a0 in range(n):
op, contact = input().strip().split(' ')
if(op=='add'):
addlist.append(contact)
else:
findlist.append(contact)
for item in findlist:
count = 0
for item2 in addlist:
if item == item2[0:len(item)]:
count += 1
print(count)
I tested 10562 entries at once and it processed instantly so if it lags for you it can be blamed on your processor

Resources