
Dtg Base
- 267 installs
- 118 repo stars
- Updated July 14, 2026
- unclecatvn/agent-skills
Helps with ai & agent building tasks.
About
dtg-base is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- dtg-base
- AI & Agent Building
- AI-coding skill
Dtg Base by the numbers
- 267 all-time installs (skills.sh)
- Ranked #2,420 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 31, 2026 (Skillselion catalog sync)
npx skills add https://github.com/unclecatvn/agent-skills --skill dtg-baseAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 267 |
|---|---|
| repo stars | ★ 118 |
| Last updated | July 14, 2026 |
| Repository | unclecatvn/agent-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
DTG Base Skill
Complete reference for DTG Base module utilities and helpers in Odoo 18.
What is DTG Base?
DTG Base is a custom abstract model (dtg_base.DTGBase) that provides common utility methods for Odoo development. It's designed to be inherited by other models to gain access to helpful utilities.
Quick Reference
| Utility | Description |
|---|---|
| Date & Period | Find first/last date of period, period iteration |
| Timezone | Convert local to UTC, UTC to local |
| Barcode | Check barcode exists, generate EAN13 |
| Batch Processing | Split large recordsets into batches |
| after_commit | Execute code after transaction commit |
| Vietnamese Text | Strip accents, convert to non-accent |
| File Utilities | Zip directories, get file size |
| Number Utilities | Round to decimal places |
---
Main Guide
File: odoo-18-dtg-base-guide.md
When to use this skill
- Working with DTG Odoo codebase
- Need date/period calculations
- Timezone conversions
- Barcode validation
- Batch processing large recordsets
- Vietnamese text processing
- File zipping utilities
---
DTGBase Abstract Model
Inherit from DTGBase
Location: addons_customs/erp/dtg_base/models/dtg_base.py
from odoo import models
class MyModel(models.Model):
_name = 'my.model'
_inherit = ['dtg_base.dtg_base']
def my_method(self):
# Now you have access to all DTGBase utilities
first_date = self.find_first_date_of_period('2024-01-15', 'month')
utc_date = self.convert_local_to_utc('2024-01-15 10:00:00')---
File Structure
agent-skills/skills/dtg-base/
├── SKILL.md # This file - master index
├── odoo-18-dtg-base-guide.md # Complete DTG Base utilities reference
└── README.md # Skill overview---
Utilities Overview
Date & Period Utilities
find_first_date_of_period(date, period_type)- Get first date of periodfind_last_date_of_period(date, period_type)- Get last date of periodperiod_iter(start_date, end_date, period_type)- Iterate over periods
Timezone Conversion
convert_local_to_utc(local_dt, tz=None)- Convert local datetime to UTCconvert_utc_to_local(utc_dt, tz=None)- Convert UTC datetime to local
Barcode Utilities
barcode_exists(barcode, exclude_id=0)- Check if barcode already existsget_ean13 barcode)- Generate/check EAN13 barcode
Batch Processing
splittor(limit=None)- Split recordset into batches for processing
String & Text Utilities
strip_accents(text)- Remove Vietnamese accents_no_accent_vietnamese(text)- Convert Vietnamese text
File Utilities
zip_dir(source_dir, output_file)- Zip a directoryzip_dirs(dirs, output_file)- Zip multiple directories_get_file_size(file_path)- Get human-readable file size
Number Utilities
round_decimal(value, decimal_places)- Round to specific decimal places
---
For detailed documentation, see [odoo-18-dtg-base-guide.md](./odoo-18-dtg-base-guide.md)
DTG Base Development Guide
This file provides guidance to AI agents when working with DTG Base utilities in Odoo 18.
What is DTG Base?
DTG Base is a custom abstract model (dtg_base.DTGBase) that provides common utility methods for Odoo development at DTG. It's inherited by other models to gain access to helpful utilities.
Location
Module: addons_customs/erp/dtg_base/
Main Model: dtg_base/models/dtg_base.py
When to Use DTG Base
| Task | Method |
|---|---|
| Get first date of month/quarter/year | find_first_date_of_period(date, 'month') |
| Get last date of month/quarter/year | find_last_date_of_period(date, 'year') |
| Convert local datetime to UTC | convert_local_to_utc(local_dt, 'Asia/Ho_Chi_Minh') |
| Convert UTC to local datetime | convert_utc_to_local(utc_dt, 'Asia/Ho_Chi_Minh') |
| Check if barcode exists | barcode_exists('1234567890123') |
| Generate EAN13 barcode | get_ean13('product_code') |
| Process large recordsets in batches | splittor(limit=100) |
| Remove Vietnamese accents | strip_accents('Tiếng Việt') |
| Zip a directory | zip_dir(source_path, output_path) |
| Get file size in readable format | _get_file_size(file_path) |
Inheritance Pattern
from odoo import models
class MyModel(models.Model):
_name = 'my.model'
_inherit = ['dtg_base.dtg_base']
def process_records(self):
# Use DTGBase utilities
for batch in self.splittor(limit=100):
# Process batch
passKey Utilities
Date & Period
# Get first date of current month
first_date = self.find_first_date_of_period(fields.Date.today(), 'month')
# Get last date of current quarter
last_date = self.find_last_date_of_period(fields.Date.today(), 'quarter')
# Iterate over months in a period
for start, end in self.period_iter('2024-01-01', '2024-12-31', 'month'):
print(f"Period: {start} to {end}")Timezone Conversion
# Convert Vietnam local time to UTC
utc_dt = self.convert_local_to_utc('2024-01-15 10:00:00', 'Asia/Ho_Chi_Minh')
# Convert UTC to Vietnam local time
local_dt = self.convert_utc_to_local(utc_dt, 'Asia/Ho_Chi_Minh')Batch Processing
# Process 1000 records in batches of 100
records = self.env['my.model'].search([])
for batch in records.splittor(limit=100):
# Process each batch
for record in batch:
# Do something
passBarcode
# Check if barcode already exists
if self.barcode_exists('1234567890123'):
raise UserError("Barcode already exists!")
# Generate EAN13 barcode
ean13 = self.get_ean13('PRODUCT123')Vietnamese Text
# Remove accents for search/comparison
search_text = self.strip_accents('Tiếng Việt') # -> 'Ties Viet'
# For comparison
if self.strip_accents(record.name) == self.strip_accents(search_term):
# Match
passPeriod Types
| Type | Description |
|---|---|
'month' | Month period |
'quarter' | Quarter period |
'year' | Year period |
'week' | Week period |
Common Timezones
| Timezone | UTC Offset |
|---|---|
'Asia/Ho_Chi_Minh' | UTC+7 |
'UTC' | UTC+0 |
'Asia/Bangkok' | UTC+7 |
'Asia/Singapore' | UTC+8 |
---
For complete reference, see [odoo-18-dtg-base-guide.md](./odoo-18-dtg-base-guide.md)
Odoo 18 DTG Base Guide
Complete reference for DTG Base module utilities and helpers.
Table of Contents
1. DTGBase Abstract Model 2. Date & Period Utilities 3. Timezone Conversion 4. Barcode Utilities 5. Batch Processing 6. after_commit Decorator 7. String & Text Utilities 8. File Utilities 9. Number Utilities
---
DTGBase Abstract Model
Inherit from DTGBase
Location: addons_customs/erp/dtg_base/models/dtg_base.py
from odoo import models, fields
class MyModel(models.Model):
_name = 'my.model'
_inherit = ['dtg.base'] # Inherit DTGBase to access all utilities
name = fields.Char()When to inherit:
- Need date/period calculation utilities
- Need timezone conversion
- Need barcode validation/generation
- Need batch processing with memory management
- Need Vietnamese text processing
- Need file zipping utilities
---
Date & Period Utilities
Period Names
Supported periods: 'hourly', 'daily', 'weekly', 'monthly', 'quarterly', 'biannually', 'annually'
Aliases also work: 'hour', 'day', 'week', 'month', 'quarter', 'biannual', 'year', 'annual'
find_first_date_of_period()
Find the first date of a period from any date within that period.
# Get first day of month from any date
date = fields.Date.to_date('2024-02-15')
first_day = self.find_first_date_of_period('monthly', date)
# Result: datetime(2024, 2, 1, 0, 0, 0)
# Get first day of week (Monday)
first_week_day = self.find_first_date_of_period('weekly', date)
# Result: datetime(2024, 2, 12, 0, 0, 0) - Monday of that week
# Get first day of quarter
first_quarter_day = self.find_first_date_of_period('quarterly', date)
# Result: datetime(2024, 1, 1, 0, 0, 0) - Q1 starts Jan 1
# With offset - start from 5th day
first_day_offset = self.find_first_date_of_period('monthly', date, start_day_offset=5)
# Result: datetime(2024, 2, 6, 0, 0, 0)find_last_date_of_period()
Find the last date of a period from any date within that period.
# Get last day of month
date = fields.Date.to_date('2024-02-15')
last_day = self.find_last_date_of_period('monthly', date)
# Result: datetime(2024, 2, 29, 23, 59, 59, 999999) - 2024 is leap year
# Get last day of quarter
last_quarter_day = self.find_last_date_of_period('quarterly', date)
# Result: datetime(2024, 3, 31, 23, 59, 59, 999999)
# When given_date is also the start date
start_date = fields.Date.to_date('2024-02-01')
last_day_from_start = self.find_last_date_of_period('monthly', start_date, date_is_start_date=True)
# Result: datetime(2024, 2, 29, 23, 59, 59, 999999)
# Custom cycle value - 2 months
last_day_2months = self.find_last_date_of_period('monthly', date, cycle_value=2)
# Result: datetime(2024, 3, 31, 23, 59, 59, 999999) - 2 month periodperiod_iter()
Generate sorted dates for periods between two dates.
# Get all month ends between two dates
dt_start = fields.Date.to_date('2024-01-15')
dt_end = fields.Date.to_date('2024-06-20')
period_dates = self.period_iter('monthly', dt_start, dt_end)
# Result: [
# date(2024, 1, 15), # start date
# date(2024, 1, 31), # end of Jan
# date(2024, 2, 29), # end of Feb
# date(2024, 3, 31), # end of Mar
# date(2024, 4, 30), # end of Apr
# date(2024, 5, 31), # end of May
# date(2024, 6, 20), # end date
# ]
# Quarterly with offset
quarterly_dates = self.period_iter('quarterly', dt_start, dt_end, start_day_offset=5)
# Result includes dates starting from 5th day of each quarterDate Difference Utilities
# Days between dates
days = self.get_days_between_dates(date_from, date_to)
# Hours between datetimes
hours = self.get_hours_between_dates(datetime_from, datetime_to)
# Weeks between dates
weeks = self.get_weeks_between_dates(date_from, date_to)
# Months between dates (float, respects odd/even months)
months = self.get_months_between_dates(date_from, date_to)
# Example: Jan 15 to Feb 14 = 0.9677 months (31 days in Jan)
# Years between dates (float, respects leap years)
years = self.get_number_of_years_between_dates(date_from, date_to)
# Days in month
days_in_month = self.get_days_of_month_from_date(date)
# Day of year (1-366)
day_of_year = self.get_day_of_year_from_date(date)
# Example: Jan 6 returns 6
# Days in year (365 or 366)
days_in_year = self.get_days_in_year(date)Other Date Utilities
# Split date into components
year, month, day = self.split_date(date)
# Next weekday
next_monday = self.next_weekday(date, weekday=0) # 0=Monday, 6=Sunday
same_weekday = self.next_weekday(date) # Same weekday next week
# Break time range at midnight
# 2024-02-02 20:00 to 2024-02-03 04:00
# -> [2024-02-02 20:00, 2024-02-03 00:00, 2024-02-03 04:00]
intervals = self.break_timerange_for_midnight(start_dt, end_dt)Period Ratio Calculation
# Calculate ratio between two periods
# Example: monthly vs daily on Feb 2024 (29 days)
ratio = self.get_ratio_between_periods('monthly', 1, 'daily', 1, given_date=date(2024, 2, 1))
# Result: 29/7
# Example: quarterly vs monthly
ratio = self.get_ratio_between_periods('quarterly', 1, 'monthly', 1)
# Result: 3.0---
Timezone Conversion
get_company_tz()
Get company timezone.
# Get current company's timezone
tz = self.get_company_tz()
# Returns: 'Asia/Ho_Chi_Minh' or 'UTC' or company's timezone
# Get specific company's timezone
tz = self.get_company_tz(company=company_record)convert_local_to_utc()
Convert local datetime to UTC.
# Convert local datetime to UTC
local_dt = datetime(2024, 2, 15, 14, 30, 0)
utc_dt = self.convert_local_to_utc(local_dt, force_local_tz_name='Asia/Ho_Chi_Minh')
# Result: datetime(2024, 2, 15, 7, 30, 0) (UTC is 7 hours behind)
# Use context tz or user tz
utc_dt = self.convert_local_to_utc(local_dt)
# With naive=True (no timezone info in result)
utc_dt_naive = self.convert_local_to_utc(local_dt, naive=True)
# Result: datetime(2024, 2, 15, 7, 30, 0) without tzinfo
# Convert date to datetime then to UTC
date_only = date(2024, 2, 15)
utc_from_date = self.convert_local_to_utc(date_only)convert_utc_to_local()
Convert UTC datetime to local timezone.
# Convert UTC to local
utc_dt = datetime(2024, 2, 15, 7, 30, 0)
local_dt = self.convert_utc_to_local(utc_dt, force_local_tz_name='Asia/Ho_Chi_Minh')
# Result: datetime(2024, 2, 15, 14, 30, 0)
# With DST handling
local_dt = self.convert_utc_to_local(utc_dt, is_dst=False)Time Conversion Utilities
# Convert datetime to float hours
# datetime(2024, 1, 1, 14, 30, 0) -> 14.5
float_hours = self.time_to_float_hour(datetime)
# Convert float hours to time
# 14.5 -> time(14, 30, 0)
time_obj = self.float_hours_to_time(14.5)
# Convert hours to string "HH:MM"
time_str = self.hours_time_string(14.5) # "14:30"
time_str = self.hours_time_string(8.5) # "08:30"
# Convert date to datetime (combines with current time)
dt = self.date_to_datetime(date_value)---
Barcode Utilities
barcode_exists()
Check if barcode exists in a model.
# Check in current model
exists = self.barcode_exists('8901234567890')
# Check in specific model
exists = self.barcode_exists('8901234567890', model_name='product.product')
# Check with custom barcode field
exists = self.barcode_exists('8901234567890', barcode_field='default_code')
# Check only active records (default)
exists = self.barcode_exists('8901234567890', inactive_rec=True)
# Check all records including inactive
exists = self.barcode_exists('8901234567890', inactive_rec=False)get_ean13()
Generate EAN-13 barcode checksum.
# Generate EAN-13 from 12-digit base
barcode = self.get_ean13('123456789012')
# Result: '1234567890128' (last digit is checksum)
# Pads with zeros if less than 12 digits
barcode = self.get_ean13('123')
# Result: '000000000123X' (padded to 12 digits + checksum)---
Batch Processing
splittor()
Split large recordsets into batches to avoid memory issues.
# Basic usage - splits into batches of PREFETCH_MAX (1000)
for batch in self.splittor(large_recordset):
# Process batch
batch.compute_expensive_field()
# Custom batch size
for batch in self.splittor(large_recordset, max_rec_in_batch=500):
# Process 500 records at a time
batch.write({'field': value})
# Maintain order - high priority items first
for batch in self.splittor(recordset, max_rec_in_batch=100, maintain_order=True):
# Batches maintain relative order
batch.process()
# No flush - keep in cache
for batch in self.splittor(recordset, flush=False):
# Records stay in cache
batch.read_only_operation()Key features:
- Automatically divides collection into equal-sized batches
- Invalidates recordset after each batch (default) to free memory
- Set
flush=Falseto keep records in cache - Use
maintain_order=Trueto preserve order across batches
---
after_commit Decorator
Execute tasks after database transaction commits.
from odoo.addons.dtg_base.models.dtg_base import after_commit
class MyModel(models.Model):
_name = 'my.model'
_inherit = ['dtg.base']
@after_commit
def send_notification_after_commit(self):
"""Send notification ONLY after transaction commits"""
for rec in self:
rec.message_post(
body=_("Record created successfully"),
message_type='notification'
)
def action_process(self):
# This will be called after commit
self.send_notification_after_commit()
return {'type': 'ir.actions.act_window_close'}Important:
- Function runs AFTER commit, in a new cursor
- Use for notifications, external API calls, emails
- If the function raises an exception, it's logged but doesn't rollback the transaction
---
String & Text Utilities
strip_accents() & _no_accent_vietnamese()
Remove accents from Vietnamese text.
# Strip accents (general + Vietnamese specific)
text = "Tiếng Việt có dấu"
no_accent = self.strip_accents(text)
# Result: "Tieng Viet khong dau"
# Direct Vietnamese conversion
vietnamese = "Xin chào, Đất Việt nước đẹp"
converted = self._no_accent_vietnamese(vietnamese)
# Result: "Xin chao, Dat Viet nuoc dep"---
File Utilities
zip_dir()
Zip a directory into bytes for storage in Binary field.
# Zip a directory
path = '/path/to/directory'
zipped_bytes = self.zip_dir(path, incl_dir=False)
# Store in binary field
self.attachment_data = zipped_bytes
# Include directory name in zip
zipped_with_dir = self.zip_dir(path, incl_dir=True)zip_dirs()
Zip multiple directories into one archive.
# Zip multiple directories
paths = ['/path/to/dir1', '/path/to/dir2']
zipped_bytes = self.zip_dirs(paths)
# Store in attachment
attachment = self.env['ir.attachment'].create({
'name': 'archives.zip',
'res_id': self.id,
'res_model': self._name,
'datas': zipped_bytes,
})_get_file_size()
Get size of file or directory.
# Get file size
file_size = self._get_file_size('/path/to/file.pdf')
# Returns: size in bytes
# Get directory size (recursive)
dir_size = self._get_file_size('/path/to/directory')
# Returns: total size in bytes (excluding symbolic links)---
Number Utilities
sum_digits()
Sum digits until result has specified number of digits.
# Sum all digits once
result = self.sum_digits(178)
# Result: 16 (1 + 7 + 8)
# Sum until single digit
result = self.sum_digits(178, number_of_digit_return=1)
# Result: 7 (1 + 6 = 7)
# Sum until 2 digits
result = self.sum_digits(9999, number_of_digit_return=2)
# Result: 36 (9 + 9 + 9 + 9 = 36)find_nearest_lucky_number()
Find nearest number where digit sum equals 9.
# Find nearest lucky number
lucky = self.find_nearest_lucky_number(178)
# Result: 171 (1 + 7 + 1 = 9)
# With rounding
lucky = self.find_nearest_lucky_number(178999, rounding=2)
# Result: 178900 (then adjusted to nearest lucky number)
# Round up
lucky = self.find_nearest_lucky_number(100, round_up=True)
# Result: 108 (1 + 0 + 8 = 9)calculate_weights()
Calculate weight percentages.
# Calculate weights as percentages
weights = self.calculate_weights(2, 6)
# Result: [0.25, 0.75] (25%, 75%)
# With precision
weights = self.calculate_weights(2, 6, precision_digits=2)
# Result: [0.25, 0.75]
# Ensure sum equals 1
assert sum(weights) == 1.0fibonacci()
Generate Fibonacci sequence.
# Generate 5 terms
fib = self.fibonacci(5)
# Result: [0, 1, 1, 2, 3]
# Deduplicate first 1
fib = self.fibonacci(5, deduplicate_1=True)
# Result: [0, 1, 2, 3] - removed duplicate 1---
Other Utilities
validate_year()
Validate and convert year to integer.
# Valid year
year = self.validate_year('2024') # Returns: 2024
year = self.validate_year(2024) # Returns: 2024
# Invalid year - raises ValidationError
year = self.validate_year('abc') # Raises ValidationError
year = self.validate_year(0) # Raises ValidationError
year = self.validate_year(10000) # Raises ValidationErroridentical_images()
Compare two Image fields.
# Compare two images
is_same = self.identical_images(img1_field, img2_field)
# Returns: True if identical, False otherwise
# Note: Does not support SVG format (PIL limitation)Unit Conversion
# Miles to kilometers
km = self.mile2km(10) # Returns: 16.09344
# Kilometers to miles
miles = self.km2mile(16) # Returns: 9.9419Week Utilities
# Get weekdays for a period (max 7 days)
weekdays = self.get_weekdays_for_period(date_from, date_to)
# Returns: {0: date, 1: date, ...} where 0=Monday, 6=Sunday---
Common Patterns
Pattern 1: Date Range by Period
def _get_period_dates(self, date_from, date_to):
"""Get all month-end dates in range"""
return self.period_iter('monthly', date_from, date_to)
def action_report_by_period(self):
date_from = fields.Date.to_date(self.env.context.get('date_from'))
date_to = fields.Date.to_date(self.env.context.get('date_to'))
# Get all period boundaries
period_dates = self._get_period_dates(date_from, date_to)
for i in range(len(period_dates) - 1):
period_start = period_dates[i]
period_end = period_dates[i + 1]
# Process each period
self._process_period(period_start, period_end)Pattern 2: Safe Timezone Conversion
def action_schedule_meeting(self):
# Get user's local timezone
tz = self.get_company_tz()
# Convert user input (local) to UTC for storage
utc_dt = self.convert_local_to_utc(
self.meeting_date,
force_local_tz_name=tz
)
self.meeting_date_utc = utc_dt
# Convert back to local for display
local_dt = self.convert_utc_to_local(
self.meeting_date_utc,
force_local_tz_name=tz
)
self.meeting_date_display = local_dtPattern 3: Batch Processing Large Recordsets
def action_recompute_all(self):
# Get all records
records = self.search([])
# Process in batches to avoid memory issues
for batch in self.splittor(records, max_rec_in_batch=500):
# Each batch is automatically invalidated after processing
for rec in batch:
rec._compute_expensive_field()Pattern 4: After-Commit Notification
@after_commit
def _send_external_notification(self):
"""Send to external API after commit"""
for rec in self:
requests.post(
'https://api.example.com/notify',
json={'record_id': rec.id, 'state': rec.state}
)
def action_confirm(self):
self.state = 'confirmed'
# Notification only sent if transaction commits
self._send_external_notification()Pattern 5: Barcode Validation
def _check_barcode_unique(self, barcode):
"""Validate barcode doesn't exist"""
if self.barcode_exists(barcode):
raise UserError(_("Barcode %s already exists") % barcode)
def create(self, vals):
if vals.get('barcode'):
self._check_barcode_unique(vals['barcode'])
return super().create(vals)---
Anti-Patterns
| Anti-Pattern | Why Bad | Correct Approach |
|---|---|---|
| Manual date calculation for periods | Error-prone, timezone issues | Use find_first_date_of_period(), find_last_date_of_period() |
| Processing all records at once | Memory issues with large datasets | Use splittor() for batch processing |
| Sending notifications before commit | Sent even if transaction rolls back | Use @after_commit decorator |
| Manual timezone conversion | DST issues, error-prone | Use convert_local_to_utc(), convert_utc_to_local() |
| Checking barcode with search() | Doesn't check inactive records | Use barcode_exists() |
---
Method Reference
Date/Period Methods
| Method | Description |
|---|---|
find_first_date_of_period(period, date, offset) | Get first date of period |
find_last_date_of_period(period, date, is_start, cycle) | Get last date of period |
period_iter(period, dt_start, dt_end, offset, cycle) | Get all period dates in range |
get_days_between_dates(dt_from, dt_to) | Days between dates |
get_months_between_dates(dt_from, dt_to) | Months between (float) |
get_number_of_years_between_dates(dt_from, dt_to) | Years between (float) |
get_hours_between_dates(dt_from, dt_to) | Hours between datetimes |
get_days_of_month_from_date(dt) | Number of days in month |
get_day_of_year_from_date(dt) | Day of year (1-366) |
get_days_in_year(dt) | Days in year (365 or 366) |
split_date(date) | Split into year, month, day |
next_weekday(date, weekday) | Get date next week |
break_timerange_for_midnight(start, end) | Split at midnight |
get_ratio_between_periods(p1, d1, p2, d2, date) | Ratio between periods |
Timezone Methods
| Method | Description |
|---|---|
get_company_tz(company) | Get company timezone |
convert_local_to_utc(dt, tz, is_dst, naive) | Local to UTC |
convert_utc_to_local(utc_dt, tz, is_dst, naive) | UTC to local |
time_to_float_hour(dt) | Datetime to float hours |
float_hours_to_time(hours, tz) | Float to time |
hours_time_string(hours) | Hours to "HH:MM" string |
date_to_datetime(date) | Date to datetime |
Barcode Methods
| Method | Description |
|---|---|
barcode_exists(barcode, model, field, active) | Check if barcode exists |
get_ean13(base_number) | Generate EAN-13 checksum |
Batch Methods
| Method | Description |
|---|---|
splittor(collection, max, order, flush) | Split into batches |
String Methods
| Method | Description |
|---|---|
strip_accents(s) | Remove all accents |
_no_accent_vietnamese(s) | Vietnamese accent removal |
File Methods
| Method | Description |
|---|---|
zip_dir(path, incl_dir) | Zip directory |
zip_dirs(paths) | Zip multiple directories |
_get_file_size(path) | Get file/dir size |
Number Methods
| Method | Description |
|---|---|
sum_digits(n, digits) | Sum digits |
find_nearest_lucky_number(n, round, up) | Find lucky number |
calculate_weights(*weights, ...) | Calculate percentages |
fibonacci(n, dedup) | Fibonacci sequence |
Other Methods
| Method | Description |
|---|---|
validate_year(year) | Validate year (1-9999) |
identical_images(img1, img2) | Compare images |
mile2km(miles) | Convert to km |
km2mile(km) | Convert to miles |
get_weekdays_for_period(from, to) | Get weekdays dict |
---
Module Info
Module: dtg_base Version: 1.0.0 Author: AnhBT Location: addons_customs/erp/dtg_base/ License: OPL-1
Dependencies: base
Files:
models/dtg_base.py- DTGBase abstract model with all utilities
DTG Base Skill
Complete reference for DTG Base module utilities and helpers in Odoo 18.
Overview
DTG Base is a custom abstract model that provides common utility methods for Odoo development. This skill contains comprehensive documentation for all DTGBase utilities.
What's Included
- Date & Period Utilities - Find first/last dates, iterate over periods
- Timezone Conversion - Convert between local time and UTC
- Barcode Utilities - Validate and generate EAN13 barcodes
- Batch Processing - Split large recordsets into manageable batches
- after_commit Decorator - Execute code after transaction commit
- Vietnamese Text - Strip accents for search/comparison
- File Utilities - Zip directories, get file sizes
- Number Utilities - Round to specific decimal places
Files
| File | Description |
|---|---|
SKILL.md | Master index and quick reference |
CLAUDE.md | AI agent guidance |
odoo-18-dtg-base-guide.md | Complete DTG Base utilities reference |
Quick Start
class MyModel(models.Model):
_name = 'my.model'
_inherit = ['dtg_base.dtg_base']
def my_method(self):
# Use DTGBase utilities
first_date = self.find_first_date_of_period('2024-01-15', 'month')
utc_date = self.convert_local_to_utc('2024-01-15 10:00:00')Links
- Full Documentation
- SKILL.md - Quick reference