details:   https://code.tryton.org/tryton/commit/90af71359399
branch:    default
user:      Cédric Krier <[email protected]>
date:      Thu May 07 13:29:24 2026 +0200
description:
        Add filename extension to Binary field
diffstat:

 sao/CHANGELOG                                              |   1 +
 sao/src/view/form.js                                       |  10 +++++++
 tryton/CHANGELOG                                           |   1 +
 tryton/tryton/gui/window/view_form/view/form_gtk/binary.py |  18 ++++++++++---
 trytond/CHANGELOG                                          |   1 +
 trytond/doc/ref/fields.rst                                 |   9 +++++-
 trytond/trytond/model/fields/binary.py                     |   4 ++-
 7 files changed, 36 insertions(+), 8 deletions(-)

diffs (134 lines):

diff -r 25afe74dbf51 -r 90af71359399 sao/CHANGELOG
--- a/sao/CHANGELOG     Thu May 07 13:28:19 2026 +0200
+++ b/sao/CHANGELOG     Thu May 07 13:29:24 2026 +0200
@@ -1,3 +1,4 @@
+* Support filename extension for Binary field
 * Use record name as fallback for filename of Binary field
 * Support filters attribute for binary and image widgets
 * Use search window to delete/remove records from xxx2Many widgets
diff -r 25afe74dbf51 -r 90af71359399 sao/src/view/form.js
--- a/sao/src/view/form.js      Thu May 07 13:28:19 2026 +0200
+++ b/sao/src/view/form.js      Thu May 07 13:29:24 2026 +0200
@@ -4595,6 +4595,12 @@
             Sao.common.get_input_data(this.input_select, function(data, 
filename) {
                 field.set_client(record, data);
                 if (filename_field) {
+                    let ext = field.description.filename_ext
+                    if (ext) {
+                        if (filename.endsWith(`.${ext}`)) {
+                            filename = filename.slice(0, -`.${ext}`.length);
+                        }
+                    }
                     filename_field.set_client(record, filename);
                 }
             }, !field.get_size);
@@ -4654,6 +4660,10 @@
                     prm = jQuery.when(name);
                 }
                 return prm.then(name => {
+                    let ext = this.field.description.filename_ext;
+                    if (ext) {
+                        name = `${name}.${ext}`;
+                    }
                     Sao.common.download_file(data, name);
                 });
             });
diff -r 25afe74dbf51 -r 90af71359399 tryton/CHANGELOG
--- a/tryton/CHANGELOG  Thu May 07 13:28:19 2026 +0200
+++ b/tryton/CHANGELOG  Thu May 07 13:29:24 2026 +0200
@@ -1,3 +1,4 @@
+* Support filename extension for Binary field
 * Use record name as fallback for filename of Binary field
 * Support filters attribute for binary and image widgets
 * Use search window to delete/remove records from xxx2Many widgets
diff -r 25afe74dbf51 -r 90af71359399 
tryton/tryton/gui/window/view_form/view/form_gtk/binary.py
--- a/tryton/tryton/gui/window/view_form/view/form_gtk/binary.py        Thu May 
07 13:28:19 2026 +0200
+++ b/tryton/tryton/gui/window/view_form/view/form_gtk/binary.py        Thu May 
07 13:29:24 2026 +0200
@@ -114,8 +114,10 @@
         uri = unquote(uri)
         self.field.set_client(self.record, url_open(uri).read())
         if self.filename_field:
-            self.filename_field.set_client(self.record,
-                os.path.basename(urlparse(uri).path))
+            filename = os.path.basename(urlparse(uri).path)
+            if ext := self.field.attrs.get('filename_ext'):
+                filename = filename.removesuffix(os.path.extsep + ext)
+            self.filename_field.set_client(self.record, filename)
 
     def get_data(self):
         if hasattr(self.field, 'get_data'):
@@ -127,11 +129,15 @@
         return data
 
     def open_(self, widget=None):
-        if not self.filename_field:
-            return
-        filename = self.filename_field.get(self.record)
+        filename = None
+        if self.filename_field:
+            filename = self.filename_field.get(self.record)
+        if not filename:
+            filename = self.record.rec_name()
         if not filename:
             return
+        if ext := self.field.attrs.get('filename_ext'):
+            filename = ''.join([filename, os.extsep, ext])
         file_path = file_write(filename, self.get_data())
         root, type_ = os.path.splitext(filename)
         if type_:
@@ -144,6 +150,8 @@
             filename = self.filename_field.get(self.record)
         if not filename:
             filename = self.record.rec_name()
+        if ext := self.field.attrs.get('filename_ext'):
+            filename = ''.join([filename, os.extsep, ext])
         filename = file_selection(_('Save As...'), filename=filename,
             action=Gtk.FileChooserAction.SAVE)
         if filename:
diff -r 25afe74dbf51 -r 90af71359399 trytond/CHANGELOG
--- a/trytond/CHANGELOG Thu May 07 13:28:19 2026 +0200
+++ b/trytond/CHANGELOG Thu May 07 13:29:24 2026 +0200
@@ -1,3 +1,4 @@
+* Add filename extension to Binary field
 * Add filters attribute for binary and image widgets
 * Move last_user and last_modification to ResourceAccessMixin
 * Add check deliverability option to validate email tool
diff -r 25afe74dbf51 -r 90af71359399 trytond/doc/ref/fields.rst
--- a/trytond/doc/ref/fields.rst        Thu May 07 13:28:19 2026 +0200
+++ b/trytond/doc/ref/fields.rst        Thu May 07 13:29:24 2026 +0200
@@ -552,8 +552,13 @@
    Name of the field that holds the data's filename.
 
    Default value is an empty string, which means the data has no filename (in
-   this case, the filename is hidden, and the "Open" button is hidden when the
-   widget is set to "image").
+   this case, the filename is hidden).
+
+.. attribute:: Binary.filename_ext
+
+   The extension to append to the :attr:`~Binary.filename`.
+
+   The default value is empty.
 
 .. attribute:: Binary.file_id
 
diff -r 25afe74dbf51 -r 90af71359399 trytond/trytond/model/fields/binary.py
--- a/trytond/trytond/model/fields/binary.py    Thu May 07 13:28:19 2026 +0200
+++ b/trytond/trytond/model/fields/binary.py    Thu May 07 13:29:24 2026 +0200
@@ -33,8 +33,9 @@
     def __init__(self, string='', help='', required=False, readonly=False,
             domain=None, states=None, on_change=None,
             on_change_with=None, depends=None, context=None, loading='lazy',
-            filename=None, file_id=None, store_prefix=None):
+            filename=None, filename_ext=None, file_id=None, store_prefix=None):
         self.filename = filename
+        self.filename_ext = filename_ext
         self.file_id = file_id
         self.store_prefix = store_prefix
         super().__init__(string=string, help=help,
@@ -165,4 +166,5 @@
         definition = super().definition(model, language)
         definition['searchable'] = False
         definition['filename'] = self.filename
+        definition['filename_ext'] = self.filename_ext
         return definition

Reply via email to