feat: Parameterize fixed asset import and deletion scripts with command-line arguments and update the README.
This commit is contained in:
parent
359b1a2278
commit
3803078318
@ -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`.
|
||||||
|
|||||||
@ -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)
|
|
||||||
|
|
||||||
import odoo
|
odoo_bin_path = os.path.abspath(args.odoo_bin_path)
|
||||||
from odoo import api, SUPERUSER_ID
|
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:
|
try:
|
||||||
odoo.tools.config.parse_config(['-c', CONF_FILE])
|
import odoo
|
||||||
registry = odoo.registry(DB_NAME)
|
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:
|
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()
|
||||||
|
|||||||
@ -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")
|
||||||
|
|
||||||
import odoo
|
args = parser.parse_args()
|
||||||
from odoo import api, SUPERUSER_ID
|
|
||||||
|
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:
|
try:
|
||||||
odoo.tools.config.parse_config(['-c', CONF_FILE])
|
import odoo
|
||||||
registry = odoo.registry(DB_NAME)
|
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:
|
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()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user