I wonder how can I add an invoice via Quickbooks API v3 using Python. A script with minimum requirements would be appreciated.
I am new to APIs so, I am interested if I can write a simple script without running server to upload invoices to QuickBooks. If not, I guess I should use Django or Flask right?
Thank you in advance.
here is a simple example of how to create a single-line Invoice with only required fields.
from quickbooks.objects import (Invoice,
SalesItemLineDetail,
SalesItemLine)
customer_ref = Ref()
customer_ref.value = 123
customer_ref.name = 'Ivan Petrov'
customer_ref.type = 'Customer'
# or customer_ref = Customer.get(123, qb=client).to_ref()
line_detail = SalesItemLineDetail()
line_detail.UnitPrice = 100 # in dollars
line_detail.Qty = 1 # quantity can be decimal
line = SalesItemLine()
line.Amount = 100 # in dollars
line.SalesItemLineDetail = line_detail
invoice = Invoice()
invoice.CustomerRef = customer_ref
invoice.Line = [line]
client = QuickBooks(...)
invoice.save(qb=client)
follow this link for more explanation www.github.com/ej2/python-quickbooks/issues/103
You can use python-quickbooks library.
There are also examples how to use it:
from intuitlib.client import AuthClient
from quickbooks import QuickBooks
auth_client = AuthClient(
client_id='CLIENT_ID',
client_secret='CLIENT_SECRET',
environment='sandbox',
redirect_uri='http://localhost:8000/callback',
)
client = QuickBooks(
auth_client=auth_client,
refresh_token='REFRESH_TOKEN',
company_id='COMPANY_ID',
)
customer = Customer()
customer.CompanyName = "Test Company"
customer.save(qb=client)
For invoice, you must have a customer who will pay, accounts for expense and income, and item of service or product that provide to the customer.
# client is your quickbook object
customer = Customer()
customer.CompanyName = "Test221wq Company"
customer.DisplayName = "Test3wrq1 Owner"
customer.PrimaryEmailAddr = EmailAddress()
customer.PrimaryEmailAddr.Address = "test1wq3#email.com"
customer.save(qb=client)
print(customer.__dict__)
income_account = Account()
income_account.Name = "Test3w1 Account"
income_account.AccountSubType = "ServiceFeeIncome"
income_account.CurrentBalanceWithSubAccounts = 500
income_account.save(qb=client)
print(income_account.__dict__)
expense_account = Account()
expense_account.Name = "Test4 Account"
expense_account.AccountSubType = "CostOfLabor"
expense_account.CurrentBalanceWithSubAccounts = 1000
expense_account.save(qb=client)
print(expense_account.__dict__)
item = Item()
item.Name = "Test Service Item"
item.IncomeAccountRef = income_account.to_ref()
item.ItemCategoryType = "Service"
item.ExpenseAccountRef = expense_account.to_ref()
item.Type = "Service"
item.save(qb=client)
print(item.__dict__)
line = SalesItemLine()
line.LineNum = 1
line.Description = "fieldworkers"
line.Amount = 100
line.SalesItemLineDetail = SalesItemLineDetail()
line.SalesItemLineDetail.ItemRef = item.to_ref()
invoice = Invoice()
invoice.CustomerRef = customer.to_ref()
invoice.Line.append(line)
invoice.save(qb=client)
print(invoice.__dict__)
This is enough to generate an invoice.
Related
I'm trying to set inventory quantity of a product in shopify using the Shopify Python Api.
As i understand it, i need to set the 'inventory_level' of the 'inventory_item' that belongs to the product, but after a few days of searching and testing i still have no luck.
Where i'm at
I have my products showing up in my store with all the data but the inventory quantity.
I'm not sure how to proceed as there's not a whole lot of documentation.
Here's my code for creating a product
def CreateShopifyProduct(data):
# CREATE PRODUCT
product = shopify.Product()
# Add stuff to product, variant and inventoryItem here
product.title = data['title']
#product.status = ""
#product.tags = data['tags']
product.body_html = data['description']
if 'catagory' in data:
product.product_type = data['category']
if 'vendor' in data:
product.vendor = data['vendor']
if 'image_url' in data:
image_path = data['image_url']
image = shopify.Image()
image.src = image_path
product.images = [image]
else:
try:
image = GetLocalImageFiles(data['id'])
product.images = [image]
except:
print("No local images found")
success = product.save() #returns false if the record is invalid
# CREATE VARIANT
variant = shopify.Variant()
if 'ean' in data:
variant.barcode = data['ean']
variant.price = data['gross_price']
variant.weight = data['weight']
#variant.count = data['inventory']
variant.inventory_management = 'shopify'
product.variants = [variant]
variant.product_id = product.id
s = variant.save()
success = product.save() #returns false if the record is invalid
# CREATE INVENTORYITEM
inventoryItem = shopify.InventoryItem()
#inventoryItem = variant.inventory_item
inventoryItem.tracked = True
inventoryItem.id = product.id
variant.inventory_quantity = data['inventory']
inventoryItem.inventory_quantity = data['inventory']
variant.inventory_item = inventoryItem
s = variant.save()
success = product.save()
#ii = inventoryItem.save() # this returns 406
#inv_level = shopify.InventoryLevel.find(inventory_item_ids=6792364982390, location_ids=61763518582)
#quantity = inv_level[0].__dict__['attributes']['available']
#shopify.InventoryLevel.set(location_id=61763518582, inventory_item_id=variant.inventory_item.id, available=data['inventory'])
#shopify.InventoryLevel.connect(61763518582, variant.inventory_item.id)
if product.errors:
#something went wrong, see new_product.errors.full_messages() for example
print("error")
print(product.errors.full_messages())
If i try to set the InventoryLevel with
shopify.InventoryLevel.set(61527654518, inventoryItem.id, 42)
# or
shopify.InventoryLevel.set(location_id=61527654518, inventory_item_id=inventoryItem.id, available=17)
I recieve a
pyactiveresource.connection.ResourceNotFound: Not Found: https://domain.myshopify.com/admin/api/2022-07/inventory_levels/set.json
You need three things to update an inventory level. One, you need a valid location ID. Two, you need the inventory item ID. Finally, you need the amount to adjust inventory to, that will adjust the inventory there to match your needs.
You should really play at the command-line and ensure you can quickly get the information you need, then try your updates. In other words, ensure you are getting a good location ID, inventory item ID and finally, that you know the amount of inventory already in Shopify. Since you have to calculate a delta change, these are the minimum steps most people take.
Note that once you get good at doing one item, you'll realize Shopify also accepts up to 100 at a time, making your updates a lot faster.
I am trying to get a list of all the org ids under organization using boto3. The current structure is like this -
Root
|
|
ou1-----OU2-----OU3
| | |
ou4 ou5 ou6
|
ou7
|
ou8
This structure may change in future more ORG units might get added some of them may be deleted so I would like to make the function dynamic. I was hoping I could provide the Root id after which it should be able to find out all the org id under it. But this seems a little complicated as there is no existing API in boto3 which lists all the ORG ids under root. I would really appreciate if someone could give guidance/suggestion
I have taken a look at -
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/organizations.html#Organizations.Client.list_children
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/organizations.html#Organizations.Client.list_parents
but not sure how to interconnect them so it can find all the org ids, below is the code that I wrote but this will only fetch 2nd layer of children, that is till org4,5 and 6
org = session.client("organizations")
response = org.list_roots()
for PolicyTypes in response["Roots"]:
parent_id = PolicyTypes["Id"]
OUlist = []
NextToken = False
while NextToken is not None:
if not NextToken:
response_iterator = org.list_organizational_units_for_parent(ParentId=parent_id, MaxResults=20)
else:
response_iterator = org.list_organizational_units_for_parent(ParentId=parent_id, MaxResults=20,
NextToken=NextToken)
OUlist = get_OUlist(OUlist, response_iterator)
try:
NextToken = response_iterator['NextToken']
except KeyError:
break
get_child_ou(org, OUlist)
def get_child_ou(org, OUlist):
for ou in OUlist:
NextToken = False
while NextToken is not None:
if not NextToken:
response_iterator = org.list_children(ParentId=ou, ChildType='ORGANIZATIONAL_UNIT', MaxResults=20)
else:
response_iterator = org.list_children(ParentId=ou, ChildType='ORGANIZATIONAL_UNIT', NextToken=NextToken,
MaxResults=20)
try:
NextToken = response_iterator['NextToken']
except KeyError:
break
for orgid in response_iterator["Children"]:
OUlist.append(orgid["Id"])
return OUlist
Simple solution
import boto3
session = boto3.Session(profile_name='default')
org = session.client('organizations')
def printout(parent_id, indent):
print(f"{'-' * indent} {parent_id}")
paginator = org.get_paginator('list_children')
iterator = paginator.paginate(
ParentId=parent_id,
ChildType='ORGANIZATIONAL_UNIT'
)
indent += 1
for page in iterator:
for ou in page['Children']:
printout(ou['Id'], indent)
if __name__ == "__main__":
rootid = org.list_roots()["Roots"][0]["Id"]
printout(rootid, 0)
import boto3
def add_ou(ids):
for id in ids:
ou_list.append(id)
child_ids = get_childs(id)
while child_ids:
if len(child_ids) > 1:
add_ou(child_ids)
child_ids = []
else:
ou_list.append(child_ids[0])
child_ids = get_childs(child_ids[0])
def get_childs(id):
childs = org_client.list_children(
ParentId=id,
ChildType='ORGANIZATIONAL_UNIT')
return [child["Id"] for child in childs["Children"]]
if __name__ == "__main__":
org_client = boto3.client('organizations')
root_id = org_client.list_roots()["Roots"][0]["Id"]
childs = get_childs(root_id)
ou_list = []
add_ou(childs)
print(ou_list)
This will loop through all organization units and print organization units Ids
In addition to #Danish's answer:
You can now use the Paginator feature for organizations.list_children (and many other API calls). This drops the need to check for NextToken, saves LOCs and enhances code readability :-)
# Lambda example
import boto3
client = boto3.client('organizations')
def lambda_handler(event, context):
root_id = client.list_roots()['Roots'][0]['Id']
ou_id_list = get_ou_ids(root_id)
print(ou_id_list)
def get_ou_ids(parent_id):
full_result = []
paginator = client.get_paginator('list_children')
iterator = paginator.paginate(
ParentId=parent_id,
ChildType='ORGANIZATIONAL_UNIT'
)
for page in iterator:
for ou in page['Children']:
# 1. Add entry
# 2. Fetch children recursively
full_result.append(ou['Id'])
full_result.extend(get_ou_ids(ou['Id']))
return full_result
I'm trying to be able to set a custom fields in NetSuite using webservices.
The WSDL I'm using is: https://webservices.netsuite.com/wsdl/v2017_2_0/netsuite.wsdl
Currently I'm testing it on creating a customer. Here's what I have so far:
def add_customer():
client = login_client()
RecordRef = client.get_type('ns0:RecordRef')
Customer = client.get_type('ns13:Customer')
customer = Customer(
companyName='TEST',
subsidiary = RecordRef(internalId='5', type='subsidiary')
)
response = client.service.add(customer)
print(response)
add_customer()
This Works perfectly, but now I'm trying to set a custom field with id custfield1
After doing some searching, I found:
http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2016_2/schema/other/customfieldlist.html?mode=package
From this link I know that I'll be needing to use CustomFieldRef, I'm just not sure how it would be implemented.
I found a way to do this:
def add_customer():
client = login_client()
RecordRef = client.get_type('ns0:RecordRef')
StringCustomFieldRef = client.get_type('ns0:StringCustomFieldRef') #StringCustomFieldRef
CustomFieldList = client.get_type('ns0:CustomFieldList') #To go from object to list
#Cust field 1
acctName = StringCustomFieldRef()
acctName.internalID = '1569'
acctName.scriptId = 'custentity_account_name'
acctName.value = 'testData'
#custField2
acctID= StringCustomFieldRef()
acctID.internalId= '1596'
acctID.scriptId= 'custentity_sf_account_id'
acctID.value = 'FIELD DATA'
Customer = client.get_type('ns13:Customer')
customer = Customer(
companyName='TEST',
entityId='TEST ID',
subsidiary = RecordRef(internalId='5', type='subsidiary'),
customFieldList = CustomFieldList([acctID,acctName]) #List of cust objects
)
response = client.service.add(customer)
print(response)
add_customer()
You have to use the Ref type for the field you are working with: https://system.na1.netsuite.com/app/help/helpcenter.nl?fid=section_n3458179.html
I need to get the order number related with its service order. Each service order has many bench orders. E.g.: If the service order number is 223 the bench orders related to that are 223-1, 223-2, 223-3... if SO number is 553, bench order numbers must be 553-1, 553-2, 553-3, etc.
I tried it several ways and I failed to do it. Please help me. I used Odoo sequence to do that, but it did not give the output as I want. Here is my code: (E.g.: 223 means work authorization number).
class MyDepots_so(models.Model):
_name = 'my_depots_so'
so_parts_ids = fields.One2many('tiq_so_parts', 'so_p_id', string='Add Part Details', invisible='1')
so_bo_ids = fields.One2many('my_depots.so_bo',
so_work_authorization = fields.Integer("Work Authorization#")
class SO_Parts(models.Model):
_name = 'tiq_so_parts'
so_p_id = fields.Many2one('my_depots_so',string='Add Service Order Part', invisible='1')
#api.model
def create(self, vals):
sequence = self.env['ir.sequence'].next_by_code('so.benchorder') or '/'
str_sequence = str(sequence)
query = """SELECT so_work_authorization FROM my_depots_so WHERE id=%d """ % (so_p_id)
self.env.cr.execute(query)
result = self.env.cr.fetchall()
result_number = json.dumps(result, ensure_ascii=False)
strip_number = result_number.strip('\' \" [] ')
work_auth_no = str(strip_number)
work_auth_no += "-"
work_auth_no += str_sequence
Ok, I think you are looking for something like this (I added a field to your tiq_so_parts model since you have to store the subsequence somewhere -where were you storing the 223-1, 223-2, 223-3... values?
I created the field part_sequence to store these values-).
class MyDepots_so(models.Model):
_name = 'my_depots_so'
so_parts_ids = fields.One2many('tiq_so_parts', 'so_p_id', string='Add Part Details', invisible='1')
so_bo_ids = fields.One2many('my_depots.so_bo',
so_work_authorization = fields.Integer("Work Authorization#")
class SO_Parts(models.Model):
_name = 'tiq_so_parts'
so_p_id = fields.Many2one('my_depots_so',string='Add Service Order Part', invisible='1')
part_sequence = fields.Char(string='Part Sequence')
#api.model
def create(self, vals):
so_part = super(SO_Parts, self).create(vals)
so_p_id = so_part.so_p_id
main_sequence = so_p_id.so_work_authorization
part_sequence = len(so_p_id.so_parts_ids)
so_part.write({
'part_sequence': str(main_sequence) + '-' + str(part_sequence),
})
return so_part
I have a legacy Google App engine code, which is having the following entity classes in Python
class AffiliateParent(db.Model):
name = db.StringProperty(required = True)
class Affiliate(db.Model):
email = db.StringProperty(required = True)
point_gain = db.IntegerProperty()
point_used = db.IntegerProperty()
#feature_upgrade = db.ListProperty(str)
modified_time = db.DateTimeProperty(auto_now = True)
I was wondering, is the following the correct way to generate unique id? Are they guarantee unique within Affiliate table?
affiliate_parent_key = AffiliateParent.all(keys_only=True).filter('name =', 'yancheng').get();
affiliate_parent = db.get(affiliate_parent_key);
# check whether affiliate exist, if not create one
affiliate_parent = db.get(affiliate_parent_key);
q = Affiliate.all()
q.ancestor(affiliate_parent)
q.filter('email =', email)
affiliate = q.get()
if not affiliate:
affiliate = Affiliate(
email = email,
point_gain = 0,
point_used = 0,
parent = affiliate_parent
)
affiliate.put()
# 4503602445942784
# is this unique?
unique_id = affiliate.key().id()
yes, if you don't supply id or key when instantiating the model, then datastore will generate a unique ID and assign it to your entity when you .put() it... thus affiliate.key.id() will be unique
you can also generate unique IDs using allocate_ids(count)
https://cloud.google.com/appengine/docs/python/datastore/functions#allocate_ids