Module III - Day 2

Python Made Easy: Science and Math Edition

Sep-Dec 2025 batch, Vikrant Patil

Date: 20 Dec 2025

Click here for All Notes

Live note are here https://vikrant.dev/python-made-easy-science-math/module3-day2.html

Please login to https://traininghub.vikrant.dev and create a notebook with name module3-day2.ipynb

© Vikrant Patil

import xlsxwriter

workbook = xlsxwriter.Workbook('image.xlsx')
worksheet = workbook.add_worksheet()

logo = '/home/vikrant/Pictures/alicante-logo.png.png'
# Original image.
worksheet.insert_image('B2', logo)

# Same size as original, despite row/col changes.
worksheet.insert_image('E8', logo)

# Make column F narrower.
worksheet.set_column('F:F', 2)

# Hide row 10 (zero indexed).
worksheet.set_row(9, None, None, {'hidden': True})

workbook.close()
%%file invoice-generator.py
import typer
import csv
import datetime
import os
import re
import xlsxwriter


alicante_data = {
    "address" : "Address: C402,Purvi Lotus Apartments;HSR 2nd sector Extn,Near SS Palya Lake,;Hosapaly,Bangalore 560068",
    "GSTIN"  :"27ASBLL55591Z0",
    "CIN" : "U74900KA2015PTC078397",
    "vendor_number":"97330282"
}

def generate_invoice_count(folder=None):
    year = datetime.datetime.now().year
    pattern = r"^AAPL-[A-Z0-9\-]+-(?P<count>\d\d\d)-" + f"{year}.xlsx$"
    p = re.compile(pattern)
    
    def get_count(text):
        m = p.match(text)
        return int(m.groupdict()['count'])
        
    if not folder:
        folder = os.getcwd()
    
    files = [f for f in os.listdir(folder) if p.match(f)]
    if files:
        last = max(files, key=get_count)
        return f"{get_count(last)+1}".zfill(3)
    else:
        return "001"

def invoice_number(customer_id):
    year = datetime.datetime.now().year
    count= generate_invoice_count()
    return f"AAPL-{customer_id}-{count}-{year}"
    

def read_po(pofile):
    with open(pofile) as f:
        d_po = csv.DictReader(f)
        return [line for line in d_po]

def read_customer_details(customerfile):
    with open(customerfile) as f:
        d_po = csv.DictReader(f)
        return next(d_po)
    

def create_invoice_excel(excelname):

    def alicante_details(worksheet):
        address_lines = alicante_data['address'].split(";")
        for i,line in enumerate(address_lines, start=10):
            worksheet.write(f"A{i}", line)
        n = 10 + len(address_lines)
        worksheet.write(f"A{n}", "GSTIN", bold)
        worksheet.write(f"B{n}", ": " + alicante_data['GSTIN'], bold)
        n = n + 1
        worksheet.write(f"A{n}", "Vendor No")
        worksheet.write(f"B{n}", ": " + alicante_data['vendor_number'])
        
    workbook = xlsxwriter.Workbook(excelname)
    worksheet = workbook.add_worksheet()

    bold = workbook.add_format({'bold': True})
    boldbig = workbook.add_format({'bold': True})
    boldbig.set_font_size(18)

    logo = '/home/vikrant/Pictures/alicante-logo.png'
    worksheet.insert_image('A1', 
                           logo,
                           {"x_scale": 0.58, "y_scale": 0.58}
                          )
    worksheet.write("D8", "INVOICE", boldbig)
    worksheet.set_column('A:A', 10)
    alicante_details(worksheet)
    
    workbook.close()

def generate_invoice(document_num:str, pofile:str, customer:str):
    po_info = (read_po(pofile))
    customer_info = read_customer_details(customer)
    invoice = invoice_number(customer_info['customer_id'])
    filename = f"{invoice}.xlsx"
    print("generating invoice", filename)
    create_invoice_excel(filename)

if __name__ == "__main__":
    typer.run(generate_invoice)
Overwriting invoice-generator.py
!python invoice-generator.py --help
                                                                                                                        

 Usage: invoice-generator.py [OPTIONS] DOCUMENT_NUM POFILE CUSTOMER                                                     

                                                                                                                        

╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────────────────────────────╮

│ *    document_num      TEXT  [required]                                                                              │

│ *    pofile            TEXT  [required]                                                                              │

│ *    customer          TEXT  [required]                                                                              │

╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮

│ --help          Show this message and exit.                                                                          │

╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯


!python invoice-generator.py 4500050005 po1.csv bosch.csv
generating invoice AAPL-BMG-6-016-2025.xlsx
import datetime
datetime.datetime.now().year
2025
import re # regular expression
year = datetime.datetime.now().year
pattern = r"^AAPL-[A-Z0-9\-]+-\d\d\d-" + f"{year}.xlsx$"
pattern
'^AAPL-[A-Z0-9\\-]+-\\d\\d\\d-2025.xlsx$'
p = re.compile(pattern)
invoice_num = "AAPL-BMG-6-006-2025.xlsx"
p.match(invoice_num)
<re.Match object; span=(0, 24), match='AAPL-BMG-6-006-2025.xlsx'>
p.match("AAPL-BMG-6-006-2025dhsjkd")
p.match("AAPL-BMG-6-006-2025.pdf")
year = datetime.datetime.now().year
pattern = r"^AAPL-[A-Z0-9\-]+-(?P<count>\d\d\d)-" + f"{year}.xlsx$"
pattern
'^AAPL-[A-Z0-9\\-]+-(?P<count>\\d\\d\\d)-2025.xlsx$'
p = re.compile(pattern)
m = p.match(invoice_num)
m
<re.Match object; span=(0, 24), match='AAPL-BMG-6-006-2025.xlsx'>
m.groupdict()['count']
'006'
m.count
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[47], line 1
----> 1 m.count

AttributeError: 're.Match' object has no attribute 'count'
def get_count(text):
        year = datetime.datetime.now().year
        pattern = r"^AAPL-[A-Z0-9\-]+-(?P<count>\d\d\d)-" + f"{year}.xlsx$"
        p = re.compile(pattern)
        m = p.match(text)
        return int(m.groupdict()['count'])
get_count(invoice_num)
6
"5".zfill(3)
'005'
import typer
import csv
import datetime
import os
import re

def generate_invoice_count(folder=None):
    year = datetime.datetime.now().year
    pattern = r"^AAPL-[A-Z0-9\-]+-(?P<count>\d\d\d)-" + f"{year}.xlsx$"
    p = re.compile(pattern)
    
    def get_count(text):
        m = p.match(text)
        return int(m.groupdict()['count'])
        
    if not folder:
        folder = os.getcwd()
    
    files = [f for f in os.listdir(folder) if p.match(f)]
    if files:
        last = max(files, key=get_count)
        return f"{get_count(last)+1}".zfill(3)
    else:
        return "001"
        
generate_invoice_count()
'001'
!touch "AAPL-BMG-6-006-2025.xlsx"
generate_invoice_count()
'007'
def invoice_number(customer_id):
    year = datetime.datetime.now().year
    count= generate_invoice_count()
    return f"AAPL-{customer_id}-{count}-{year}"
invoice_number("BMG-6")
'AAPL-BMG-6-007-2025'
%%file bosch.csv
customer_id,GSTIN,address
BMG-6,29AAACM9840P1ZP,"Bosch Limited;Naganathapura plant;PB No 6887,Electronic City PO;Bangalore-560100, Karnataka" 
Overwriting bosch.csv