deisy 5 роки тому
коміт
a52ab52934

+ 3 - 0
__init__.py

@@ -0,0 +1,3 @@
+# -*- encoding: utf-8 -*-
+
+import models

+ 24 - 0
__openerp__.py

@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+{
+    'name': "Eiru Pos GPS",
+    'summary': """Añade campo para GPS en cliente para ser usado en el POS.""",
+    'author': "Eiru",
+    'website': "http://www.eiru.com.py",
+    'category': 'Point of Sale',
+    'version': '0.1',
+    'depends': [
+                'base',
+                'point_of_sale',
+                'eiru_num2word',
+                ],
+    "data": [
+        "template.xml",
+        'views/res_partner.xml',
+    ],
+    'qweb': [
+        'static/src/xml/pos.xml',
+    ],
+    'license': 'AGPL-3',
+    'installable': True,
+    'auto_install': False,
+}

+ 2 - 0
models/__init__.py

@@ -0,0 +1,2 @@
+# -*- encoding: utf-8 -*-
+import res_partner

+ 8 - 0
models/res_partner.py

@@ -0,0 +1,8 @@
+# -*- encoding: utf-8 -*-
+
+from openerp import models, fields, api, _
+
+class res_partner(models.Model):
+    _inherit = 'res.partner'
+
+    gps = fields.Char('GPS')

BIN
static/description/icon.png


+ 34 - 0
static/src/js/customer.js

@@ -0,0 +1,34 @@
+function pos_customer(instance, module){
+
+    var PosModelSuper = module.PosModel;
+    module.PosModel = module.PosModel.extend({
+        load_server_data: function(){
+            var self = this;
+            var loaded = PosModelSuper.prototype.load_server_data.call(this);
+
+            loaded = loaded.then(function(){
+                return self.fetch(
+                    'res.partner',
+                    ['gps'],
+                );
+
+            }).then(function(partners){
+                $.each(partners, function(){
+                    $.extend(self.db.get_partner_by_id(this.id) || {}, this);
+                });
+                return $.when();
+            });
+            return loaded;
+        },
+    });
+}
+
+(function(){
+    var _super = window.openerp.point_of_sale;
+    window.openerp.point_of_sale = function(instance){
+        _super(instance);
+        var module = instance.point_of_sale;
+
+        pos_customer_extra_field(instance, module);
+    };
+})();

+ 7 - 0
static/src/js/main.js

@@ -0,0 +1,7 @@
+openerp.eiru_pos_gps = function(instance) {
+    var module = instance.point_of_sale;
+    pos_screens(instance, module);
+    pos_customer(instance, module);
+
+    instance.web.client_actions.add('pos.ui', 'instance.point_of_sale.PosWidget');
+};

+ 387 - 0
static/src/js/screen.js

@@ -0,0 +1,387 @@
+function pos_screens(instance, module){ //module is instance.point_of_sale
+    var QWeb = instance.web.qweb,
+    _t = instance.web._t;
+
+    var round_pr = instance.web.round_precision
+
+    module.ClientListScreenWidget = module.ScreenWidget.extend({
+        template: 'ClientListScreenWidget',
+
+        init: function(parent, options){
+            this._super(parent, options);
+        },
+
+        show_leftpane: false,
+
+        auto_back: true,
+
+        show: function(){
+            var self = this;
+            this._super();
+
+            this.renderElement();
+            this.details_visible = false;
+            this.old_client = this.pos.get('selectedOrder').get('client');
+            this.new_client = this.old_client;
+
+            this.$('.back').click(function(){
+                self.pos_widget.screen_selector.back();
+            });
+
+            this.$('.next').click(function(){
+                self.save_changes();
+                self.pos_widget.screen_selector.back();
+            });
+
+            this.$('.new-customer').click(function(){
+                self.display_client_details('edit',{
+                    'country_id': self.pos.company.country_id,
+                });
+            });
+
+            var partners = this.pos.db.get_partners_sorted(1000);
+            this.render_list(partners);
+
+            this.reload_partners();
+
+            if( this.old_client ){
+                this.display_client_details('show',this.old_client,0);
+            }
+
+            this.$('.client-list-contents').delegate('.client-line','click',function(event){
+                self.line_select(event,$(this),parseInt($(this).data('id')));
+            });
+
+            var search_timeout = null;
+
+            if(this.pos.config.iface_vkeyboard && this.pos_widget.onscreen_keyboard){
+                this.pos_widget.onscreen_keyboard.connect(this.$('.searchbox input'));
+            }
+
+            this.$('.searchbox input').on('keyup',function(event){
+                clearTimeout(search_timeout);
+
+                var query = this.value;
+
+                search_timeout = setTimeout(function(){
+                    self.perform_search(query,event.which === 13);
+                },70);
+            });
+
+            this.$('.searchbox .search-clear').click(function(){
+                self.clear_search();
+            });
+        },
+        barcode_client_action: function(code){
+            if (this.editing_client) {
+                this.$('.detail.barcode').val(code.code);
+            } else if (this.pos.db.get_partner_by_ean13(code.code)) {
+                this.display_client_details('show',this.pos.db.get_partner_by_ean13(code.code));
+            }
+        },
+        perform_search: function(query, associate_result){
+            if(query){
+                var customers = this.pos.db.search_partner(query);
+                this.display_client_details('hide');
+                if ( associate_result && customers.length === 1){
+                    this.new_client = customers[0];
+                    this.save_changes();
+                    this.pos_widget.screen_selector.back();
+                }
+                this.render_list(customers);
+            }else{
+                var customers = this.pos.db.get_partners_sorted();
+                this.render_list(customers);
+            }
+        },
+        clear_search: function(){
+            var customers = this.pos.db.get_partners_sorted(1000);
+            this.render_list(customers);
+            this.$('.searchbox input')[0].value = '';
+            this.$('.searchbox input').focus();
+        },
+        render_list: function(partners){
+            var contents = this.$el[0].querySelector('.client-list-contents');
+            contents.innerHTML = "";
+            for(var i = 0, len = Math.min(partners.length,1000); i < len; i++){
+                var partner    = partners[i];
+                var clientline_html = QWeb.render('ClientLine',{widget: this, partner:partners[i]});
+                var clientline = document.createElement('tbody');
+                clientline.innerHTML = clientline_html;
+                clientline = clientline.childNodes[1];
+
+                if( partners === this.new_client ){
+                    clientline.classList.add('highlight');
+                }else{
+                    clientline.classList.remove('highlight');
+                }
+
+                contents.appendChild(clientline);
+            }
+        },
+        save_changes: function(){
+            if( this.has_client_changed() ){
+                this.pos.get('selectedOrder').set_client(this.new_client);
+            }
+        },
+        has_client_changed: function(){
+            if( this.old_client && this.new_client ){
+                return this.old_client.id !== this.new_client.id;
+            }else{
+                return !!this.old_client !== !!this.new_client;
+            }
+        },
+        toggle_save_button: function(){
+            var $button = this.$('.button.next');
+            if (this.editing_client) {
+                $button.addClass('oe_hidden');
+                return;
+            } else if( this.new_client ){
+                if( !this.old_client){
+                    $button.text(_t('Set Customer'));
+                }else{
+                    $button.text(_t('Change Customer'));
+                }
+            }else{
+                $button.text(_t('Deselect Customer'));
+            }
+            $button.toggleClass('oe_hidden',!this.has_client_changed());
+        },
+        line_select: function(event,$line,id){
+            var partner = this.pos.db.get_partner_by_id(id);
+            this.$('.client-list .lowlight').removeClass('lowlight');
+            if ( $line.hasClass('highlight') ){
+                $line.removeClass('highlight');
+                $line.addClass('lowlight');
+                this.display_client_details('hide',partner);
+                this.new_client = null;
+                this.toggle_save_button();
+            }else{
+                this.$('.client-list .highlight').removeClass('highlight');
+                $line.addClass('highlight');
+                var y = event.pageY - $line.parent().offset().top
+                this.display_client_details('show',partner,y);
+                this.new_client = partner;
+                this.toggle_save_button();
+            }
+        },
+        partner_icon_url: function(id){
+            return '/web/binary/image?model=res.partner&id='+id+'&field=image_small';
+        },
+
+        // ui handle for the 'edit selected customer' action
+        edit_client_details: function(partner) {
+            this.display_client_details('edit',partner);
+        },
+
+        // ui handle for the 'cancel customer edit changes' action
+        undo_client_details: function(partner) {
+            if (!partner.id) {
+                this.display_client_details('hide');
+            } else {
+                this.display_client_details('show',partner);
+            }
+        },
+
+        // what happens when we save the changes on the client edit form -> we fetch the fields, sanitize them,
+        // send them to the backend for update, and call saved_client_details() when the server tells us the
+        // save was successfull.
+        save_client_details: function(partner) {
+            var self = this;
+
+            var fields = {}
+            this.$('.client-details-contents .detail').each(function(idx,el){
+                fields[el.name] = el.value;
+            });
+
+            if (!fields.name) {
+                this.pos_widget.screen_selector.show_popup('error',{
+                    message: _t('A Customer Name Is Required'),
+                });
+                return;
+            }
+
+            if (this.uploaded_picture) {
+                fields.image = this.uploaded_picture;
+            }
+
+            fields.id           = partner.id || false;
+            fields.country_id   = fields.country_id || false;
+            fields.ean13        = fields.ean13 ? this.pos.barcode_reader.sanitize_ean(fields.ean13) : false;
+
+            new instance.web.Model('res.partner').call('create_from_ui',[fields]).then(function(partner_id){
+                self.saved_client_details(partner_id, fields);
+            },function(err,event){
+                event.preventDefault();
+                self.pos_widget.screen_selector.show_popup('error',{
+                    'message':_t('Error: Could not Save Changes'),
+                    'comment':_t('Your Internet connection is probably down.'),
+                });
+            });
+        },
+
+        // what happens when we've just pushed modifications for a partner of id partner_id
+        saved_client_details: function(partner_id, fields){
+            var self = this;
+            this.reload_partners().then(function(){
+                var partner = self.pos.db.get_partner_by_id(partner_id);
+                partner['gps'] = fields.gps;
+                if (partner) {
+                    self.new_client = partner;
+                    self.toggle_save_button();
+                    self.display_client_details('show',partner);
+                } else {
+                    // should never happen, because create_from_ui must return the id of the partner it
+                    // has created, and reload_partner() must have loaded the newly created partner.
+                    self.display_client_details('hide');
+                }
+            });
+        },
+
+        // resizes an image, keeping the aspect ratio intact,
+        // the resize is useful to avoid sending 12Mpixels jpegs
+        // over a wireless connection.
+        resize_image_to_dataurl: function(img, maxwidth, maxheight, callback){
+            img.onload = function(){
+                var png = new Image();
+                var canvas = document.createElement('canvas');
+                var ctx    = canvas.getContext('2d');
+                var ratio  = 1;
+
+                if (img.width > maxwidth) {
+                    ratio = maxwidth / img.width;
+                }
+                if (img.height * ratio > maxheight) {
+                    ratio = maxheight / img.height;
+                }
+                var width  = Math.floor(img.width * ratio);
+                var height = Math.floor(img.height * ratio);
+
+                canvas.width  = width;
+                canvas.height = height;
+                ctx.drawImage(img,0,0,width,height);
+
+                var dataurl = canvas.toDataURL();
+                callback(dataurl);
+            }
+        },
+
+        // Loads and resizes a File that contains an image.
+        // callback gets a dataurl in case of success.
+        load_image_file: function(file, callback){
+            var self = this;
+            if (!file.type.match(/image.*/)) {
+                this.pos_widget.screen_selector.show_popup('error',{
+                    message:_t('Unsupported File Format'),
+                    comment:_t('Only web-compatible Image formats such as .png or .jpeg are supported'),
+                });
+                return;
+            }
+
+            var reader = new FileReader();
+            reader.onload = function(event){
+                var dataurl = event.target.result;
+                var img     = new Image();
+                img.src = dataurl;
+                self.resize_image_to_dataurl(img,800,600,callback);
+            }
+            reader.onerror = function(){
+                self.pos_widget.screen_selector.show_popup('error',{
+                    message:_t('Could Not Read Image'),
+                    comment:_t('The provided file could not be read due to an unknown error'),
+                });
+            };
+            reader.readAsDataURL(file);
+        },
+
+        // This fetches partner changes on the server, and in case of changes,
+        // rerenders the affected views
+        reload_partners: function(){
+            var self = this;
+            return this.pos.load_new_partners().then(function(){
+                self.render_list(self.pos.db.get_partners_sorted(1000));
+
+                // update the currently assigned client if it has been changed in db.
+                var curr_client = self.pos.get_order().get_client();
+                if (curr_client) {
+                    self.pos.get_order().set_client(self.pos.db.get_partner_by_id(curr_client.id));
+                }
+            });
+        },
+
+        // Shows,hides or edit the customer details box :
+        // visibility: 'show', 'hide' or 'edit'
+        // partner:    the partner object to show or edit
+        // clickpos:   the height of the click on the list (in pixel), used
+        //             to maintain consistent scroll.
+        display_client_details: function(visibility,partner,clickpos){
+            var self = this;
+            var contents = this.$('.client-details-contents');
+            var parent   = this.$('.client-list').parent();
+            var scroll   = parent.scrollTop();
+            var height   = contents.height();
+
+            contents.off('click','.button.edit');
+            contents.off('click','.button.save');
+            contents.off('click','.button.undo');
+            contents.on('click','.button.edit',function(){ self.edit_client_details(partner); });
+            contents.on('click','.button.save',function(){ self.save_client_details(partner); });
+            contents.on('click','.button.undo',function(){ self.undo_client_details(partner); });
+            this.editing_client = false;
+            this.uploaded_picture = null;
+
+            if(visibility === 'show'){
+                contents.empty();
+                contents.append($(QWeb.render('ClientDetails',{widget:this,partner:partner})));
+
+                var new_height   = contents.height();
+
+                if(!this.details_visible){
+                    if(clickpos < scroll + new_height + 20 ){
+                        parent.scrollTop( clickpos - 20 );
+                    }else{
+                        parent.scrollTop(parent.scrollTop() + new_height);
+                    }
+                }else{
+                    parent.scrollTop(parent.scrollTop() - height + new_height);
+                }
+
+                this.details_visible = true;
+                this.toggle_save_button();
+            } else if (visibility === 'edit') {
+                this.editing_client = true;
+                contents.empty();
+                contents.append($(QWeb.render('ClientDetailsEdit',{widget:this,partner:partner})));
+                this.toggle_save_button();
+
+                contents.find('.image-uploader').on('change',function(event){
+                    self.load_image_file(event.target.files[0],function(res){
+                        if (res) {
+                            contents.find('.client-picture img, .client-picture .fa').remove();
+                            contents.find('.client-picture').append("<img src='"+res+"'>");
+                            contents.find('.detail.picture').remove();
+                            self.uploaded_picture = res;
+                        }
+                    });
+                });
+            } else if (visibility === 'hide') {
+                contents.empty();
+                if( height > scroll ){
+                    contents.css({height:height+'px'});
+                    contents.animate({height:0},400,function(){
+                        contents.css({height:''});
+                    });
+                }else{
+                    parent.scrollTop( parent.scrollTop() - height);
+                }
+                this.details_visible = false;
+                this.toggle_save_button();
+            }
+        },
+        close: function(){
+            this._super();
+        },
+    });
+
+    
+}

+ 32 - 0
static/src/xml/pos.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates id="template" xml:space="preserve">
+
+    <!-- Mostrar Formulario -->
+    <t t-extend="ClientDetails">
+      <t t-jquery="div.client-details-left>div:last-child" t-operation="before">
+        <div class='client-detail'>
+          <span class='label'>GPS</span>
+          <t t-if='partner.gps'>
+            <span class='detail client-gps'>
+              <a t-att-href='partner.gps' target="_blank" style="color:blue">
+                <t t-esc='partner.gps'/>
+              </a>
+            </span>
+          </t>
+          <t t-if='!partner.gps'>
+            <span class='detail client-gps empty'>N/A</span>
+          </t>
+        </div>
+      </t>
+    </t>
+
+    <!-- Editar Formulario -->
+    <t t-extend="ClientDetailsEdit">
+      <t t-jquery="div.client-details-left>div:last-child" t-operation="before">
+        <div class='client-detail'>
+          <span class='label'>GPS</span>
+          <input class='detail client-gps' name='gps' t-att-value='partner.gps' placeholder='GPS'></input>
+        </div>
+      </t>
+    </t>
+</templates>

+ 13 - 0
template.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <template id="assets_backends_js" name="eiru_pos_gps assests" inherit_id="web.assets_backend">
+            <xpath expr="." position="inside">
+               <script type="text/javascript" src="/eiru_pos_gps/static/src/js/main.js"></script>
+               <script type="text/javascript" src="/eiru_pos_gps/static/src/js/customer.js"></script>
+               <script type="text/javascript" src="/eiru_pos_gps/static/src/js/screen.js"></script>
+            </xpath>
+        </template>
+    </data>
+</openerp>

+ 15 - 0
views/res_partner.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<openerp>
+    <data>
+      <record id="gps_partner_form" model="ir.ui.view">
+            <field name="name">gps_partner_form</field>
+            <field name="model">res.partner</field>
+            <field name="inherit_id" ref="base.view_partner_form"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='website']" position="after">
+                  <field name="gps" widget="url"/>
+                </xpath>
+            </field>
+        </record>
+    </data>
+</openerp>