feat: Parameterize fixed asset import and deletion scripts with command-line arguments and update the README.

This commit is contained in:
Suherdy Yacob 2026-01-22 08:21:06 +07:00
parent 359b1a2278
commit 3803078318
3 changed files with 129 additions and 67 deletions

View File

@ -1,31 +1,70 @@
# Fixed Asset Import Script # Fixed Asset Import Tools
This script imports fixed assets from `Fixed Asset Kipas.xlsx` into Odoo 17 database `kipasdbclone5`. This folder contains scripts to manage the import and lifecycle of fixed assets in Odoo 17.
## Features ## 1. Import Script (`import_fixed_assets.py`)
- **Avoids Double Posting**: Sets assets to 'Running' (Open) state manually, bypassing the Journal Entry creation for Asset Recognition. Imports assets from an Excel file, handling depreciation calculation and creating the assets in "Running" state to avoid opening balance duplication.
- **Depreciation Calculation**: Adjusts the "Accumulated Depreciation Per Dec 31" from Excel to "Per Oct 31" (Opening Balance Date) by subtracting 2 months of depreciation.
- **Model Handling**: Automatically maps categories. Creates `Peralatan Dapur` model if missing (copying from `Peralatan Inventaris`). ### Features
- **Cutoff Date**: Skips assets acquired after Oct 31, 2025. - **Avoids Double Posting**: Sets assets to 'Running' manually.
- **Asset Code**: Maps Column B ("Kode Barang") to `asset_code`.
- **Historical Cleanup**: Deletes draft moves `<= Cutoff Date` to keep the books clean.
- **Auto-Model**: Creates missing asset models (e.g. "PERALATAN DAPUR") on the fly.
### Usage
Run the script providing the path to `odoo-bin`, `odoo.conf`, the Excel file, and the database name:
## Usage
Run the script using the Odoo virtual environment:
```bash ```bash
/home/suherdy/Pythoncode/odoo17/.venv/bin/python /home/suherdy/Pythoncode/odoo17/scripts/import_fixed_assets.py /path/to/venv/bin/python scripts/import_fixed_assets.py \
<path_to_odoo_bin> \
<path_to_odoo_conf> \
<path_to_excel_file> \
<database_name>
``` ```
## Logic Details **Example:**
1. **Accumulated Depreciation**: ```bash
- Uses Excel column R (Accum Depr Dec 31). /home/suherdy/Pythoncode/odoo17/.venv/bin/python scripts/import_fixed_assets.py \
- `Accum Oct 31 = Accum Dec 31 - (2 * Monthly Depreciation)`. /home/suherdy/Pythoncode/odoo17/odoo/odoo-bin \
- If asset is fully depreciated (End Date <= Oct 31), uses `Accum Dec 31` as is. /home/suherdy/Pythoncode/odoo17/odoo.conf \
2. **State**: "/home/suherdy/Pythoncode/odoo17/Fixed Asset Kipas.xlsx" \
- Assets are created in `draft`. kipasdbclone5
- `compute_depreciation_board()` is called to generate Draft moves for future depreciation (subtracted by imported amount). ```
- `state` is manually Set to `open`.
- Result: No historical moves posted. Future moves are Draft (to be posted by cron/user). No Asset Recognition entry.
## Prerequisites ---
- `openpyxl`
- `python-dateutil` ## 2. Post Depreciation (`post_depreciation.py`)
- Odoo configuration file at `../odoo.conf` Posts all **Draft** depreciation entries found in the system up to a specific date (default: today). This is useful to "catch up" depreciation for Nov/Dec 2025 after import.
### Usage
```bash
/home/suherdy/Pythoncode/odoo17/.venv/bin/python scripts/post_depreciation.py
```
*Note: You may need to edit the `POST_UP_TO_DATE` variable inside the script to target a specific date.*
---
## 3. Delete All Assets (`delete_all_assets.py`)
**⚠ WARNING**: This script deletes **ALL** fixed assets and their related journal entries (posted or draft). Use this only if you need to wipe clean and re-import.
### Usage
Run the script providing the path to `odoo-bin`, `odoo.conf`, and the database name:
```bash
/path/to/venv/bin/python scripts/delete_all_assets.py \
<path_to_odoo_bin> \
<path_to_odoo_conf> \
<database_name>
```
**Example:**
```bash
/home/suherdy/Pythoncode/odoo17/.venv/bin/python scripts/delete_all_assets.py \
/home/suherdy/Pythoncode/odoo17/odoo/odoo-bin \
/home/suherdy/Pythoncode/odoo17/odoo.conf \
kipasdbclone5
```
## Requirements
1. **Modules**: The `asset_code_field` custom module (in `customaddons/`) must be installed.
2. **Python Packages**: `openpyxl`, `python-dateutil`.

View File

@ -1,24 +1,38 @@
import sys import sys
import os import os
# ---------------- CONFIGURATION ---------------- import argparse
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
os.chdir(PROJECT_ROOT)
ODOO_PATH = os.path.join(PROJECT_ROOT, 'odoo') def main():
CONF_FILE = os.path.join(PROJECT_ROOT, 'odoo.conf') parser = argparse.ArgumentParser(description="Delete All Fixed Assets from Odoo")
DB_NAME = 'kipasdbclone5' parser.add_argument("odoo_bin_path", help="Path to odoo-bin executable")
parser.add_argument("conf_path", help="Path to odoo.conf")
parser.add_argument("db_name", help="Database name")
if ODOO_PATH not in sys.path: args = parser.parse_args()
sys.path.append(ODOO_PATH)
odoo_bin_path = os.path.abspath(args.odoo_bin_path)
conf_path = os.path.abspath(args.conf_path)
db_name = args.db_name
# Add Odoo to sys.path
odoo_root = os.path.dirname(odoo_bin_path)
if odoo_root not in sys.path:
sys.path.append(odoo_root)
# Change CWD to config directory to handle relative paths in config
os.chdir(os.path.dirname(conf_path))
try:
import odoo import odoo
from odoo import api, SUPERUSER_ID from odoo import api, SUPERUSER_ID
except ImportError:
print(f"Error: Could not import 'odoo' module from {odoo_root}. Make sure odoo-bin path is correct.")
sys.exit(1)
def delete_assets(): print(f"Initializing Odoo Environment for database: {db_name}...")
print(f"Initializing Odoo Environment for database: {DB_NAME}...")
try: try:
odoo.tools.config.parse_config(['-c', CONF_FILE]) odoo.tools.config.parse_config(['-c', conf_path])
registry = odoo.registry(DB_NAME) registry = odoo.registry(db_name)
except Exception as e: except Exception as e:
print(f"Error initializing Odoo: {e}") print(f"Error initializing Odoo: {e}")
return return
@ -49,12 +63,6 @@ def delete_assets():
moves.unlink() # Deleting moves first cleans up the relation moves.unlink() # Deleting moves first cleans up the relation
# 3. Reset Assets to Draft # 3. Reset Assets to Draft
# Some assets might be 'open' or 'close' or 'cancelled'.
# To delete, they often need to be in draft or cancelled state depending on logic,
# but unlink() in Odoo 17 account_asset usually checks if they are NOT in open/paused/close.
# So we must write state = draft.
# Check for assets that are not draft
non_draft_assets = assets.filtered(lambda a: a.state != 'draft') non_draft_assets = assets.filtered(lambda a: a.state != 'draft')
if non_draft_assets: if non_draft_assets:
print(f"Setting {len(non_draft_assets)} assets to draft state...") print(f"Setting {len(non_draft_assets)} assets to draft state...")
@ -74,4 +82,4 @@ def delete_assets():
traceback.print_exc() traceback.print_exc()
if __name__ == "__main__": if __name__ == "__main__":
delete_assets() main()

View File

@ -1,31 +1,46 @@
import sys import sys
import os import os
import argparse
import openpyxl import openpyxl
from datetime import datetime, date from datetime import datetime, date
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
# ---------------- CONFIGURATION ---------------- # Constants
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
# Change CWD to Project Root so relative paths in odoo.conf work
os.chdir(PROJECT_ROOT)
ODOO_PATH = os.path.join(PROJECT_ROOT, 'odoo')
CONF_FILE = os.path.join(PROJECT_ROOT, 'odoo.conf')
EXCEL_FILE = os.path.join(PROJECT_ROOT, 'Fixed Asset Kipas.xlsx')
DB_NAME = 'kipasdbclone5'
CUTOFF_DATE = date(2025, 10, 31) CUTOFF_DATE = date(2025, 10, 31)
if ODOO_PATH not in sys.path: def main():
sys.path.append(ODOO_PATH) parser = argparse.ArgumentParser(description="Import Fixed Assets to Odoo")
parser.add_argument("odoo_bin_path", help="Path to odoo-bin executable")
parser.add_argument("conf_path", help="Path to odoo.conf")
parser.add_argument("excel_path", help="Path to the Excel file")
parser.add_argument("db_name", help="Database name")
args = parser.parse_args()
odoo_bin_path = os.path.abspath(args.odoo_bin_path)
conf_path = os.path.abspath(args.conf_path)
excel_path = os.path.abspath(args.excel_path)
db_name = args.db_name
# Add Odoo to sys.path
odoo_root = os.path.dirname(odoo_bin_path)
if odoo_root not in sys.path:
sys.path.append(odoo_root)
# Change CWD to config directory to handle relative paths in config (like addons_path)
os.chdir(os.path.dirname(conf_path))
try:
import odoo import odoo
from odoo import api, SUPERUSER_ID from odoo import api, SUPERUSER_ID
except ImportError:
print(f"Error: Could not import 'odoo' module from {odoo_root}. Make sure odoo-bin path is correct.")
sys.exit(1)
def import_assets(): print(f"Initializing Odoo Environment for database: {db_name}...")
print(f"Initializing Odoo Environment for database: {DB_NAME}...")
try: try:
odoo.tools.config.parse_config(['-c', CONF_FILE]) odoo.tools.config.parse_config(['-c', conf_path])
registry = odoo.registry(DB_NAME) registry = odoo.registry(db_name)
except Exception as e: except Exception as e:
print(f"Error initializing Odoo: {e}") print(f"Error initializing Odoo: {e}")
return return
@ -35,7 +50,7 @@ def import_assets():
print("Connected to Odoo.") print("Connected to Odoo.")
try: try:
ensure_models(env) ensure_models(env)
process_import(env) process_import(env, excel_path)
cr.commit() cr.commit()
print("Changes committed to database.") print("Changes committed to database.")
except Exception as e: except Exception as e:
@ -100,9 +115,9 @@ def ensure_models(env):
env['account.asset'].create(vals) env['account.asset'].create(vals)
print(f"Created model '{config['name']}'.") print(f"Created model '{config['name']}'.")
def process_import(env): def process_import(env, excel_file):
print(f"Reading Excel file: {EXCEL_FILE}...") print(f"Reading Excel file: {excel_file}...")
wb = openpyxl.load_workbook(EXCEL_FILE, data_only=True) wb = openpyxl.load_workbook(excel_file, data_only=True)
ws = wb.active ws = wb.active
current_category_name = None current_category_name = None
@ -232,4 +247,4 @@ def process_import(env):
print(f"\nTotal Assets Imported: {count}") print(f"\nTotal Assets Imported: {count}")
if __name__ == "__main__": if __name__ == "__main__":
import_assets() main()