Εισαγωγή
Το πεδίο Monetary στο Odoo δεν είναι απλά ένας αριθμός — είναι το στοιχείο που «ξέρει» νόμισμα. Σε πρώτη ματιά μοιάζει με Float, αλλά έχει επιπλέον λογική μορφοποίησης, στρογγυλοποίησης και συσχέτισης με το νόμισμα της εγγραφής. Μόλις το κατανοήσετε, δεν θα θελήσετε πια να αποθηκεύετε χρηματικές τιμές με απλό Float.
Όταν βλέπετε στο Odoo το συνολικό ποσό μιας πώλησης, το τελικό ποσό ενός τιμολογίου ή την τιμή ενός προϊόντος, πίσω κρύβεται συνήθως ένα Monetary πεδίο. Αυτά τα πεδία βρίσκονται διάσπαρτα στο μοντέλο δεδομένων και αναλαμβάνουν τη σωστή εμφάνιση νομισμάτων, τη στρογγυλοποίηση και την ακρίβεια με διακριτικό τρόπο.
Αυτός ο οδηγός απευθύνεται σε developers, συμβούλους και τεχνικά προσανατολισμένους χρήστες που θέλουν να καταλάβουν σε βάθος το Monetary πεδίο. Είτε φτιάχνετε custom module, είτε ακολουθείτε tutorial για πεδία στο Odoo, είτε απλά ψάχνετε γιατί τα ποσά στρογγυλοποιούνται αλλιώς — εδώ θα βρείτε τις απαντήσεις που χρειάζεστε.
Τι είναι το πεδίο “Monetary” στο Odoo
Η τύπος fields.Monetary είναι βασικό κομμάτι του Odoo framework και προορίζεται ειδικά για τιμές σε νόμισμα: τιμές προϊόντων, ποσά τιμολογίων, σύνολα, προϋπολογισμοί — γενικά για κάθε αριθμό που αντιπροσωπεύει χρήμα.
Το χαρακτηριστικό που το ξεχωρίζει από το κοινό Float είναι ότι πάντα συνδέεται με νόμισμα. Το Monetary πεδίο «γνωρίζει» το νόμισμα του και βασίζεται σε αυτό για τον αριθμό δεκαδικών και τους κανόνες στρογγυλοποίησης.
Πώς εμφανίζεται στην διεπαφή
Στο UI του Odoo, ένα Monetary πεδίο εμφανίζεται ήδη μορφοποιημένο σύμφωνα με το συνδεδεμένο νόμισμα — για παράδειγμα «€ 1.234,50» ή «$ 1,234.50», ανάλογα με τις ρυθμίσεις του συγκεκριμένου νομίσματος. Τα δεκαδικά και το σύμβολο ακολουθούν την καρτέλα του νομίσματος.
Το πεδίο είναι επεξεργάσιμο σε φόρμες, εμφανίζεται σωστά σε λίστες και ενσωματώνεται ομαλά σε πίβοτ και οικονομικές αναφορές. Ο τελικός χρήστης δεν χρειάζεται να σκεφτεί τίποτα για τη μορφοποίηση — το Odoo το αναλαμβάνει.
Ο τύπος δεδομένων στη βάση
Στο επίπεδο βάσης δεδομένων, το Monetary αποθηκεύεται ως float (double precision) στην PostgreSQL. Η πληροφορία για το νόμισμα δεν είναι στην ίδια στήλη· προέρχεται από σχετιζόμενη εγγραφή res.currency μέσω ενός Many2one πεδίου στο ίδιο μοντέλο.
Ο διαχωρισμός τιμής και νομίσματος είναι σκόπιμος: κρατά τα πεδία της βάσης καθαρά και επιτρέπει να αλλάζει κανείς νόμισμα ανεξάρτητα από το αποθηκευμένο ποσό, όταν αυτό χρειάζεται.
Πώς λειτουργεί το πεδίο
Κατανοώντας αυτά τα μηχανικά σημεία θα μειώσετε τα προβλήματα στρογγυλοποίησης και προβολής που συχνά εμφανίζονται σε custom αναπτύξεις Odoo.
Η παράμετρος currency_field
Κάθε Monetary πεδίο πρέπει να δείχνει σε ένα Many2one πεδίο προς res.currency. Από προεπιλογή το Odoo περιμένει πεδίο με όνομα currency_id, αλλά μπορείτε να το υπερκαλύψετε με την παράμετρο currency_field:
amount = fields.Monetary(string='Amount', currency_field='currency_id')
Αν το πεδίο νομίσματος λείπει ή δεν έχει τιμή, το Odoo θα χρησιμοποιήσει το νόμισμα της εταιρείας ως fallback. Αυτό αποφεύγει σφάλματα, αλλά σε πολυνομισματικά περιβάλλοντα μπορεί να οδηγήσει σε λανθασμένη εμφάνιση — γι' αυτό δηλώστε πάντα ρητά το πεδίο νομίσματος.
Στρογγυλοποίηση και ακρίβεια
Η βασική διαφορά μεταξύ Monetary και Float είναι ο τρόπος στρογγυλοποίησης. Το μοντέλο res.currency ορίζει πόσα δεκαδικά και ποιος παράγοντας στρογγυλοποίησης ισχύει για κάθε νόμισμα. Το Odoo εφαρμόζει αυτούς τους κανόνες όταν διαβάζει ή εμφανίζει Monetary τιμές.
Έτσι, μια εσωτερική τιμή 1.2349999 για νόμισμα EUR θα εμφανιστεί ως 1.23 (ή σύμφωνα με τους κανόνες του νομίσματος), όχι ως 1.235. Αυτό είναι κρίσιμο για υπολογισμούς φόρων, σύνολα τιμολογίων και συμφωνίες κοντών — η χρήση απλού Float σε τέτοια σημεία οδηγεί σε δύσκολα ιχνηλατήσιμες αποκλίσεις.
Συνεργασία με το ORM του Odoo
Στο Odoo ORM, όταν διαβάζετε ένα Monetary πεδίο λαμβάνετε Python float. Το πλαίσιο νομίσματος προέρχεται από το συνδεδεμένο πεδίο νομίσματος στην ίδια εγγραφή. Στον Python κώδικα, για να διατηρήσετε την ακρίβεια, χρησιμοποιήστε τη μέθοδο round() του νομίσματος για ενδιάμεσα αποτελέσματα:
rounded_value = self.currency_id.round(self.amount)
Αυτό βοηθά να αποφευχθούν συσσώρευση σφαλμάτων κινητής υποδιαστολής σε αθροίσματα πολλών γραμμών ή σε επαναλαμβανόμενους υπολογισμούς.
Monetary πεδία σε QWeb reports
Στα QWeb πρότυπα αναφορών τα Monetary πεδία συνδέονται με ειδικό widget που τα μορφοποιεί σωστά σε PDF και web reports:
<span t-esc="record.amount"
t-options='{"widget": "monetary", "display_currency": record.currency_id}'/>
Έτσι διασφαλίζεται ότι το σωστό σύμβολο νομίσματος και τα δεκαδικά εμφανίζονται σε κάθε παραγόμενο έγγραφο, ανεξάρτητα από το νόμισμα της εγγραφής.
Περιπτώσεις χρήσης στις επιχειρήσεις
Τα Monetary πεδία υπάρχουν σε όλο το standard Odoo. Παρακάτω πέντε πρακτικά παραδείγματα που δείχνουν γιατί έχουν σημασία στις καθημερινές ροές εργασίας.
1. Πωλήσεις: Τιμές προϊόντων και σύνολα παραγγελίας
Πεδία όπως price_unit, price_subtotal και amount_total σε παραγγελίες πώλησης και γραμμές είναι Monetary. Σεβαστούν αυτόματα το νόμισμα που έχει επιλέξει ο πελάτης, το οποίο ενδέχεται να διαφέρει από το νόμισμα λειτουργίας της εταιρείας.
Όταν ένας υπάλληλος καταχωρεί παραγγελία σε USD για εταιρεία που λειτουργεί σε EUR, το Odoo εμφανίζει, στρογγυλοποιεί και μετατρέπει σωστά χάρη στην σύνδεση του Monetary με το νόμισμα της εγγραφής.
2. Λογιστική: Ποσά τιμολογίων και γραμμές φόρων
Στη λογιστική, κάθε στήλη ποσών σε ένα τιμολόγιο είναι Monetary: amount_untaxed, amount_tax, amount_total. Το νόμισμα του τιμολογίου καθορίζει τη στρογγυλοποίηση αυτών των πεδίων.
Αυτό δεν είναι λεπτομέρεια — λανθασμένη στρογγυλοποίηση στους φορολογικούς υπολογισμούς δημιουργεί ανισορροπίες στα ημερολόγια που είναι δύσκολο να επιλυθούν. Η στρογγυλοποίηση με γνώση νομίσματος αποτρέπει τέτοια προβλήματα.
3. CRM: Εκτιμώμενο Έσοδο στις ευκαιρίες
Το expected_revenue σε μια ευκαιρία CRM είναι Monetary. Οι ομάδες πωλήσεων καταγράφουν αξίες σε νόμισμα του prospect, ενώ τα dashboard μετατρέπουν σε εταιρικό νόμισμα για ανάλυση προσώπου—όλα λειτουργούν ομαλά λόγω της νομισματικής πληροφορίας του πεδίου.
Αυτή η συμπεριφορά δουλεύει γιατί τα Monetary πεδία κουβαλούν παράλληλα την πληροφορία του νομίσματος μαζί με τον αριθμό.
4. Προμήθειες: Τιμές προμηθευτών και παραγγελίες αγοράς
Οι παραγγελίες αγοράς χρησιμοποιούν Monetary για τιμές μονάδας και σύνολα, συνδεδεμένα με το νόμισμα του προμηθευτή. Ένα τιμολόγιο προμηθευτή σε JPY αντιμετωπίζεται με τον ίδιο τρόπο όπως ένα σε EUR — το Monetary αναλαμβάνει την ακρίβεια και την εμφάνιση χωρίς χειροκίνητες ενέργειες.
5. Custom πεδία: Παρακολούθηση προϋπολογισμών και στόχων
Συχνά ζητείται να προστεθεί προϋπολογισμός ή στόχος εσόδων σε έργο, τμήμα ή προσαρμοσμένο μοντέλο. Στις περιπτώσεις αυτές το Monetary είναι η σωστή επιλογή: ενσωματώνεται στο νόμισμα εταιρείας, εμφανίζεται σωστά και συμπεριφέρεται προβλέψιμα σε αναφορές και εξαγωγές.
Χρησιμοποιώντας Float για τέτοια πεδία είναι δυνατή λύση τεχνικά, αλλά γρήγορα οδηγεί σε ασυνέπεια εμφάνισης και σφάλματα στρογγυλοποίησης σε πολυνομισματικά σενάρια.
Δημιουργία ή προσαρμογή του πεδίου
Υπάρχουν δύο βασικοί τρόποι για να προσθέσετε Monetary πεδίο σε μοντέλο Odoo: μέσω Odoo Studio χωρίς κώδικα ή μέσω custom Python module για πλήρη έλεγχο.
Χρήση Odoo Studio
Το Odoo Studio περιλαμβάνει τύπο Monetary στο περιβάλλον δημιουργίας πεδίων. Όταν προσθέτετε τέτοιο πεδίο, το Studio δημιουργεί αυτόματα και ένα currency_id αν δεν υπάρχει ήδη στο μοντέλο. Είναι ο πιο γρήγορος τρόπος για business users που δεν γράφουν κώδικα.
Σημειώστε ότι τα Studio πεδία παίρνουν πρόθεμα x_ (π.χ. x_studio_budget). Αν το μοντέλο ήδη περιέχει currency_id, το νέο Monetary θα το χρησιμοποιήσει. Αν όχι, το Studio θα δημιουργήσει ξεχωριστό πεδίο νομίσματος — όταν υπάρχουν πολλά Monetary πεδία στο ίδιο μοντέλο, αξίζει να ελέγξετε αν μοιράζονται το ίδιο currency field ή χρειάζονται ξεχωριστά.
Για απλά σενάρια, το Studio είναι ο πιο γρήγορος και ασφαλής τρόπος δημιουργίας πεδίων για χρήστες χωρίς δικαιώματα ανάπτυξης.
Τεχνική προσέγγιση: Python fields
Σε custom module, το Monetary χρειάζεται δύο δηλώσεις: το ίδιο το πεδίο και το συνδεδεμένο πεδίο νομίσματος. Αυτός είναι ο συνηθισμένος τρόπος στην ανάπτυξη Odoo με Python.
from odoo import fields, models
class ProjectTask(models.Model):
_inherit = 'project.task'
x_budget = fields.Monetary(
string='Budget',
currency_field='x_budget_currency_id',
)
x_budget_currency_id = fields.Many2one(
comodel_name='res.currency',
string='Budget Currency',
default=lambda self: self.env.company.currency_id,
)
Είναι πρακτικό να ορίσετε το νόμισμα της εταιρείας ως default για εσωτερικά πεδία. Έτσι το πεδίο δεν θα εμφανίζεται κενό σε νέες εγγραφές και θα διατηρεί σωστή μορφοποίηση από την αρχή.
Υπολογιζόμενα Monetary πεδία
Τα Monetary δουλεύουν καλά ως computed πεδία. Αν χρειάζεται να αθροίσετε γραμμές ή να εφαρμόσετε τύπο που επιστρέφει χρηματικό αποτέλεσμα, χρησιμοποιήστε computed Monetary πεδίο με το κατάλληλο compute method.
x_total_budget = fields.Monetary(
string='Total Budget',
currency_field='currency_id',
compute='_compute_total_budget',
store=True,
)
@api.depends('x_line_ids.x_amount')
def _compute_total_budget(self):
for record in self:
record.x_total_budget = sum(record.x_line_ids.mapped('x_amount'))
Το store=True είναι σημαντικό αν θέλετε να φιλτράρετε, ταξινομήσετε ή να κάνετε ομαδοποιήσεις με το πεδίο σε λίστες ή αναφορές. Τα μη αποθηκευόμενα computed πεδία δεν μπορούν να χρησιμοποιηθούν σε ORM domain φίλτρα.
Προσθήκη Monetary πεδίου μέσω API
Αν χρειάζεται να δημιουργήσετε πεδία προγραμματιστικά (π.χ. σε σενάριο απομακρυσμένης ρύθμισης), μπορείτε να προσθέσετε Monetary πεδίο μέσω του ir.model.fields μέσω XML-RPC.
models.execute_kw(ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_budget',
'field_description': 'Budget',
'model_id': model_id,
'ttype': 'monetary',
'currency_field': 'currency_id',
'state': 'manual',
}]
)
Αυτό είναι μέρος του ευρύτερου σετ εργαλείων προσαρμογής του Odoo μέσω XML-RPC και καλύπτεται αναλυτικά σε άλλο περιεχόμενο της σειράς αυτής.
Καλές πρακτικές
Το Monetary πεδίο είναι απλό στη χρήση όταν γνωρίζετε τα πρότυπα. Ακολουθούν πρακτικές που κρατούν την υλοποίηση καθαρή και αποφεύγουν προβλήματα στο μέλλον.
1. Μην χρησιμοποιείτε Float για χρηματικές τιμές
Αυτό είναι ο κανόνας αριθμός ένα: αν ένα πεδίο αντιπροσωπεύει τιμή σε νόμισμα (τιμή, ποσό, σύνολο, προϋπολογισμός), χρησιμοποιήστε fields.Monetary. Το Float δεν έχει ενημέρωση για νόμισμα και δεν στρογγυλοποιεί σωστά ανά νόμισμα.
2. Δηλώστε πάντα ρητά το πεδίο νομίσματος
Μην βασίζεστε στο default fallback του Odoo εκτός αν το πεδίο currency_id υπάρχει πράγματι στο μοντέλο. Θέστε την παράμετρο currency_field και δηλώστε το αντίστοιχο Many2one προς res.currency για να αποφύγετε σιωπηρές fallback συμπεριφορές σε πολυνομισματικά περιβάλλοντα.
3. Ορίστε ένα προεπιλεγμένο νόμισμα
Για εσωτερικά πεδία που θα χρησιμοποιούν συνήθως το νόμισμα της εταιρείας, βάλτε default: default=lambda self: self.env.company.currency_id. Έτσι το πεδίο δεν θα φαίνεται κενό σε νέες εγγραφές και θα διατηρεί σωστή εμφάνιση.
4. Χρησιμοποιήστε store=True σε computed Monetary πεδία που θα αναζητούνται
Αν το computed Monetary πεδίο πρόκειται να χρησιμοποιηθεί σε φίλτρα ή ταξινομήσεις, βάλτε store=True. Τα μη αποθηκευόμενα δεν μπορούν να χρησιμοποιηθούν στα ORM domains και αυτό προκαλεί σύγχυση κατά το στήσιμο dashboards.
5. Στρογγυλοποιείτε ενδιάμεσα με currency.round()
Σε Python κώδικα με πολλαπλά βήματα αριθμητικών πράξεων σε Monetary τιμές, εφαρμόζετε self.currency_id.round(value) σε κάθε ουσιώδες βήμα αντί μόνο στο τέλος. Τα σφάλματα κινητής υποδιαστολής αθροίζονται και η έγκαιρη στρογγυλοποίηση μειώνει αποκλίσεις στα σύνολα.
6. Να είστε προσεκτικοί σε multi-currency αναφορές
Όταν αθροίζετε Monetary τιμές από εγγραφές με διαφορετικά νομίσματα, μην αθροίζετε τα ακατέργαστα νούμερα. Μετατρέψτε πρώτα τα ποσά σε κοινό νόμισμα χρησιμοποιώντας res.currency.compute() ή κάντε την αναφορά νομισματικά εξειδικευμένη. Η ανάμειξη νομισμάτων σε ένα άθροισμα δίνει στατιστικά σωστά αλλά οικονομικά άχρηστα νούμερα.
Συνηθισμένα λάθη
Ακόμα και έμπειροι developers κάνουν λάθη με Monetary πεδία. Ακολουθούν τα πιο συνηθισμένα και πώς να τα αποφύγετε.
Σφάλμα 1: Λείπει πεδίο νομίσματος
Το πιο συνηθισμένο λάθος είναι να προσθέσετε Monetary χωρίς το αντίστοιχο Many2one νομίσματος. Αν το currency_id δεν υπάρχει, το Odoo θα κάνει σιωπηλό fallback στην εταιρική νομισματική ρύθμιση σε κάποιες περιπτώσεις και θα πετάξει σφάλμα σε άλλες. Δημιουργήστε πάντα μαζί το πεδίο νομίσματος.
Σφάλμα 2: Δύο Monetary πεδία που μοιράζονται το ίδιο πεδίο νομίσματος αλλά προορίζονται για διαφορετικά νομίσματα
Αν έχετε δύο Monetary πεδία στο ίδιο μοντέλο που πρέπει να αποθηκεύουν ποσά σε διαφορετικά νομίσματα (π.χ. πελατειακή τιμή σε EUR και κόστος προμηθευτή σε USD), δεν μπορούν να μοιράζονται το ίδιο currency_id. Κάθε ένα χρειάζεται δική του αναφορά νομίσματος. Διαφορετικά το ένα νόμισμα θα υπερισχύει και θα προκύψουν λανθασμένα δεδομένα και συγχύσεις στο UI.
Σφάλμα 3: Διαφορές στρογγυλοποίησης σε αθροίσματα μεταξύ νομισμάτων
Το άθροισμα Monetary τιμών από διαφορετικά νομίσματα φαίνεται συχνά λάθος επειδή προσθέτετε EUR με USD σαν να ήταν το ίδιο νόμισμα. Αυτό είναι κλασικό λάθος αναφορών σε πολυεθνικές. Κανονικοποιήστε σε ένα νόμισμα πριν αθροίσετε.
Σφάλμα 4: Συγκρίσεις με κινητή υποδιαστολή σε ORM αναζητήσεις
Η αναζήτηση με ακριβή ισότητα σε Monetary (π.χ. amount = 10.0) μπορεί να χάσει εγγραφές λόγω της φύσης των float στην αποθήκευση. Χρησιμοποιήστε εύρος (>= και <=) με μικρή απόκλιση ή εφαρμόστε στρογγυλοποίηση πριν τη σύγκριση στον Python κώδικα.
Σφάλμα 5: Αγνόηση στρογγυλοποίησης κατά την εισαγωγή δεδομένων
Κατά την εισαγωγή CSV/XML-RPC, τα Monetary νούμερα αποθηκεύονται όπως δίνονται χωρίς αυτόματη στρογγυλοποίηση. Αν τα εισερχόμενα δεδομένα έχουν περισσότερα δεκαδικά από αυτά που επιτρέπει το νόμισμα, το αποτέλεσμα θα εμφανίζεται διαφορετικά και μπορεί να προκύψουν μικρές αποκλίσεις σε σύνολα. Εφαρμόστε στρογγυλοποίηση στην εισαγωγή ή προεπεξεργαστείτε τα δεδομένα πριν τα στείλετε στο Odoo.
Συμπέρασμα
Το πεδίο Monetary φαίνεται απλό αλλά κρύβει σημαντική συμπεριφορά: σύνδεση με νόμισμα, σωστή στρογγυλοποίηση και συνεπή μορφοποίηση σε όλο το σύστημα και τις αναφορές.
Η σωστή χρήση του — πάντα με ρητή σχέση σε πεδίο νομίσματος και ποτέ με αντικατάσταση από απλό Float για χρηματικές τιμές — θα σας γλιτώσει από προβλήματα που είναι δύσκολο να εντοπιστούν σε παραγωγικό περιβάλλον. Το data model του Odoo βασίζεται σε αυτό για έναν καλό λόγο.
Είτε ακολουθείτε οδηγό ανάπτυξης, προσαρμόζετε ένα στάνταρ module είτε χτίζετε κάτι καινούργιο, η σωστή διαχείριση των Monetary πεδίων είναι θεμέλιος λίθος για αξιόπιστη διαχείριση χρημάτων στο Odoo.
Χρειάζεστε βοήθεια με την υλοποίηση Odoo;
Στη Dasolo βοηθάμε εταιρείες να υλοποιήσουν, να προσαρμόσουν και να βελτιστοποιήσουν το Odoo σε κάθε κλίμακα και ρύθμιση. Είτε χρειάζεστε καθαρό data model, στρατηγική για custom πεδία, υποστήριξη multi-currency ή πλήρη rollout, η ομάδα μας έχει την εμπειρία για να το κάνει σωστά.
Αν έχετε ερωτήσεις για τα Monetary πεδία ή οποιοδήποτε άλλο κομμάτι της υλοποίησής σας, θα χαρούμε να βοηθήσουμε. Επικοινωνήστε μαζί μας και ας συζητήσουμε το project σας.