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
- **Avoids Double Posting**: Sets assets to 'Running' (Open) state manually, bypassing the Journal Entry creation for Asset Recognition.
- **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`).
- **Cutoff Date**: Skips assets acquired after Oct 31, 2025.
## 1. Import Script (`import_fixed_assets.py`)
Imports assets from an Excel file, handling depreciation calculation and creating the assets in "Running" state to avoid opening balance duplication.
### Features
- **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
/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
1. **Accumulated Depreciation**:
- Uses Excel column R (Accum Depr Dec 31).
- `Accum Oct 31 = Accum Dec 31 - (2 * Monthly Depreciation)`.
- If asset is fully depreciated (End Date <= Oct 31), uses `Accum Dec 31` as is.
2. **State**:
- Assets are created in `draft`.
- `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.
**Example:**
```bash
/home/suherdy/Pythoncode/odoo17/.venv/bin/python scripts/import_fixed_assets.py \
/home/suherdy/Pythoncode/odoo17/odoo/odoo-bin \
/home/suherdy/Pythoncode/odoo17/odoo.conf \
"/home/suherdy/Pythoncode/odoo17/Fixed Asset Kipas.xlsx" \
kipasdbclone5
```
## Prerequisites
- `openpyxl`
- `python-dateutil`
- Odoo configuration file at `../odoo.conf`
---
## 2. Post Depreciation (`post_depreciation.py`)
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 os
# ---------------- CONFIGURATION ----------------
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
os.chdir(PROJECT_ROOT)
import argparse
ODOO_PATH = os.path.join(PROJECT_ROOT, 'odoo')
CONF_FILE = os.path.join(PROJECT_ROOT, 'odoo.conf')
DB_NAME = 'kipasdbclone5'
def main():
parser = argparse.ArgumentParser(description="Delete All Fixed Assets from 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("db_name", help="Database name")
if ODOO_PATH not in sys.path:
sys.path.append(ODOO_PATH)
args = parser.parse_args()
import odoo
from odoo import api, SUPERUSER_ID
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))
def delete_assets():
print(f"Initializing Odoo Environment for database: {DB_NAME}...")
try:
odoo.tools.config.parse_config(['-c', CONF_FILE])
registry = odoo.registry(DB_NAME)
import odoo
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)
print(f"Initializing Odoo Environment for database: {db_name}...")
try:
odoo.tools.config.parse_config(['-c', conf_path])
registry = odoo.registry(db_name)
except Exception as e:
print(f"Error initializing Odoo: {e}")
return
@ -49,12 +63,6 @@ def delete_assets():
moves.unlink() # Deleting moves first cleans up the relation
# 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')
if non_draft_assets:
print(f"Setting {len(non_draft_assets)} assets to draft state...")
@ -74,4 +82,4 @@ def delete_assets():
traceback.print_exc()
if __name__ == "__main__":
delete_assets()
main()

View File

@ -1,31 +1,46 @@
import sys
import os
import argparse
import openpyxl
from datetime import datetime, date
from dateutil.relativedelta import relativedelta
# ---------------- CONFIGURATION ----------------
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'
# Constants
CUTOFF_DATE = date(2025, 10, 31)
if ODOO_PATH not in sys.path:
sys.path.append(ODOO_PATH)
def main():
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")
import odoo
from odoo import api, SUPERUSER_ID
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))
def import_assets():
print(f"Initializing Odoo Environment for database: {DB_NAME}...")
try:
odoo.tools.config.parse_config(['-c', CONF_FILE])
registry = odoo.registry(DB_NAME)
import odoo
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)
print(f"Initializing Odoo Environment for database: {db_name}...")
try:
odoo.tools.config.parse_config(['-c', conf_path])
registry = odoo.registry(db_name)
except Exception as e:
print(f"Error initializing Odoo: {e}")
return
@ -35,7 +50,7 @@ def import_assets():
print("Connected to Odoo.")
try:
ensure_models(env)
process_import(env)
process_import(env, excel_path)
cr.commit()
print("Changes committed to database.")
except Exception as e:
@ -100,9 +115,9 @@ def ensure_models(env):
env['account.asset'].create(vals)
print(f"Created model '{config['name']}'.")
def process_import(env):
print(f"Reading Excel file: {EXCEL_FILE}...")
wb = openpyxl.load_workbook(EXCEL_FILE, data_only=True)
def process_import(env, excel_file):
print(f"Reading Excel file: {excel_file}...")
wb = openpyxl.load_workbook(excel_file, data_only=True)
ws = wb.active
current_category_name = None
@ -232,4 +247,4 @@ def process_import(env):
print(f"\nTotal Assets Imported: {count}")
if __name__ == "__main__":
import_assets()
main()