Přejít na obsah
Odoo Menu
  • Přihlásit se
  • Vyzkoušejte zdarma
  • Aplikace
    Finance
    • Účetnictví
    • Fakturace
    • Výdaje
    • Spreadsheet (BI)
    • Dokumenty
    • Podpisy
    Prodej
    • CRM
    • Prodej
    • POS Obchod
    • POS Restaurace
    • Předplatné
    • Pronájem
    Webové stránky
    • Webové stránky
    • E-shop
    • Blog
    • Fórum
    • Živý chat
    • eLearning
    Dodavatelský řetězec
    • Sklad
    • Výroba
    • PLM
    • Nákup
    • Údržba
    • Kvalita
    Lidské zdroje
    • Zaměstnanci
    • Nábor
    • Volno
    • Hodnocení zaměstnanců
    • Doporučení
    • Vozový park
    Marketing
    • Marketing sociálních sítí
    • Emailový marketing
    • SMS Marketing
    • Události
    • Marketingová automatizace
    • Dotazníky
    Služby
    • Projekt
    • Časové výkazy
    • Práce v terénu
    • Helpdesk
    • Plánování
    • Schůzky
    Produktivita
    • Diskuze
    • Umělá inteligence
    • IoT
    • VoIP
    • Znalosti
    • WhatsApp
    Aplikace třetích stran Odoo Studio Odoo cloudová platforma
  • Branže
    Maloobchod
    • Knihkupectví
    • Obchod s oblečením
    • Obchod s nábytkem
    • Potraviny
    • Obchod s hardwarem
    • Hračkářství
    Jídlo a pohostinství
    • Bar a Pub
    • Restaurace
    • Fast Food
    • Penzion
    • Distributor nápojů
    • Hotel
    Nemovitost
    • Realitní kancelář
    • Architektonická firma
    • Stavba
    • Správa nemovitostí
    • Zahradnictví
    • Asociace vlastníků nemovitosti
    Poradenství
    • Účetní firma
    • Odoo Partner
    • Marketingová agentura
    • Právník
    • Akvizice talentů
    • Audit a certifikace
    Výroba
    • Textil
    • Kov
    • Nábytek
    • Jídlo
    • Pivovar
    • Korporátní dárky
    Zdraví a fitness
    • Sportovní klub
    • Prodejna brýli
    • Fitness Centrum
    • Wellness praktikové
    • Lékárna
    • Kadeřnictví
    Transakce
    • Údržbář
    • Podpora IT & hardware
    • Systémy solární energie
    • Výrobce obuvi
    • Úklidové služby
    • Služby HVAC
    Ostatní
    • Nezisková organizace
    • Agentura pro životní prostředí
    • Pronájem billboardů
    • Fotografování
    • Leasing jízdních kol
    • Prodejce softwaru
    Procházet všechna odvětví
  • Komunita
    Edukační program
    • Tutoriály
    • Dokumentace
    • Certifikace
    • Vzdělávání
    • Blog
    • Podcast
    Podpora vzdělávání
    • Vzdělávací program
    • Scale Up! Hra na firmu
    • Navštivte Odoo
    Získat software
    • Stáhnout
    • Porovnejte edice
    • Verze
    Spolupráce
    • Github
    • Fórum
    • Události
    • Překlady
    • Stát se partnerem
    • Služby pro partnery
    • Registrujte svou účetní firmu
    Získat služby
    • Najít partnera
    • Najít účetní
    • Setkejte se s poradcem
    • Implementační služby
    • Zákaznické reference
    • Podpora
    • Upgrady
    Github Youtube Twitter Linkedin Instagram Facebook Spotify
    +1 (650) 691-3277
    Dohodnout demo
  • Ceník
  • Pomoc
You need to be registered to interact with the community.
All Posts Lidé Odznaky
Štítky (View all)
odoo accounting v14 pos v15
O tomto fóru
You need to be registered to interact with the community.
All Posts Lidé Odznaky
Štítky (View all)
odoo accounting v14 pos v15
O tomto fóru
Pomoc

POS barcode search not working in offline mode (need hybrid logic)

Odebírat

Get notified when there's activity on this post

This question has been flagged
serverposrpcJs
582 Zobrazení
Avatar
Ashilkrishna

Hi everyone,

I am implementing a custom barcode search feature in POS.

 Current behavior:
  • Online mode

    • Server barcode search works
    • Real-time stock works
    • allow_negative_pos_sale works
  • Offline mode

    • I want:

      • Local barcode search
      • Cached stock check
      • No crash
❌ Problem:

When POS is offline, barcode search is not working properly (product not found or stock shows 0 even if available).

 My Code (JS):
/** @odoo-module **/

import { patch } from "@web/core/utils/patch";
import { Navbar } from "@point_of_sale/app/navbar/navbar";
import { useRef } from "@odoo/owl";

patch(Navbar.prototype, {
patchName: "pos_barcode_search.Navbar",
setup() {
super.setup();
this.barcodeInput = useRef("barcodeInput");
},
async barcodeKeyHandler(ev) {
if (ev.key === "Enter") {
console.log("Barcode handler triggered!");
const barcode = this.barcodeInput.el.value.trim();
console.log("barcode", barcode);
console.log("this.pos", this.pos);

if (barcode && this.pos) {
// First try to find the product in local models
let product = this.pos.models["product.product"].getBy("barcode", barcode);

// If not found locally, try product packaging
if (!product) {
const productPackaging = this.pos.models["product.packaging"].getBy("barcode", barcode);
product = productPackaging && productPackaging.product_id;
}

// If still not found, search on the server
if (!product) {
try {
const records = await this.pos.data.callRelated(
"pos.session",
"find_product_by_barcode",
[this.pos.session.id, barcode, this.pos.config.id]
);
await this.pos.processProductAttributes();

if (records && records["product.product"].length > 0) {
product = records["product.product"][0];
await this.pos._loadMissingPricelistItems([product]);
}
} catch (error) {
console.error("Error searching for product by barcode:", error);
}
}

if (product) {
// Ensure we have the 'type' field on the product
let productType = product.type;
if (productType === undefined) {
const orm = this.env.services.orm;
const typeData = await orm.read('product.product', [product.id], ['type']);
productType = typeData[0]?.type;
}

if (productType === 'product' || productType === 'consu') { // Both storable and consumable products need stock check
// Check if product allows negative POS sales
const allowNegativeSale = product.allow_negative_pos_sale;
console.log("[BARCODE SEARCH] Product:", product.name, "allow_negative_pos_sale:", allowNegativeSale);
console.log("[BARCODE SEARCH] Full product data:", product);
console.log("[BARCODE SEARCH] Product ID:", product.id);
console.log("[BARCODE SEARCH] All product keys:", Object.keys(product));

// If field is not available, try to fetch it from server
let finalAllowNegativeSale = allowNegativeSale;
if (allowNegativeSale === undefined || allowNegativeSale === null) {
console.log("[BARCODE SEARCH] Field not available in product data, fetching from server...");
try {
const orm = this.env.services.orm;
const fieldData = await orm.read('product.product', [product.id], ['allow_negative_pos_sale']);
finalAllowNegativeSale = fieldData[0]?.allow_negative_pos_sale || false;
console.log("[BARCODE SEARCH] Fetched from server:", finalAllowNegativeSale);
} catch (error) {
console.error("[BARCODE SEARCH] Error fetching field from server:", error);
finalAllowNegativeSale = false;
}
}

// CONDITION: If product has exemption enabled, skip stock restriction
if (finalAllowNegativeSale) {
console.log("[BARCODE SEARCH] Product has exemption enabled - skipping stock restriction");
// Proceed with adding product without stock check
} else {
console.log("[BARCODE SEARCH] Product has no exemption - applying stock restriction");
// Stock check logic from pos_stock_restriction.js
const orm = this.env.services.orm;
const stockData = await orm.read('product.product', [product.id], ['qty_available']);
const qty_available = stockData[0]?.qty_available ?? 0;
console.log("Qty In hand", qty_available);

// Get the current order and count how many of this product are already in the order
const order = this.pos.get_order();
let qty_in_order = 0;
if (order) {
const lines = order.get_orderlines();
console.log("Order lines:", lines);
lines.forEach(line => {
const lineProduct = line.get_product ? line.get_product() : line.product;
// Use get_quantity() if available, otherwise fallback to line.quantity
const lineQty = line.get_quantity ? line.get_quantity() : line.quantity;
console.log("Line product:", lineProduct, "Line product id:", lineProduct && lineProduct.id, "Target product id:", product.id, "Line qty:", lineQty);
if (lineProduct && lineProduct.id === product.id) {
qty_in_order += lineQty;
console.log("Qty in order (matched):", qty_in_order);
}
});
}

// The quantity to add per scan
const qty_needed = 1;

if (qty_available < qty_in_order + qty_needed) {
this.env.services.notification.add(
`Out of stock: ${product.display_name || product.name}`,
{ type: "danger" }
);
return;
}
}
await this.pos.addLineToCurrentOrder({ product_id: product }, {}, false);
this.barcodeInput.el.value = "";
} else {
// Not a storable product (e.g., service or consumable), add without stock check
await this.pos.addLineToCurrentOrder({ product_id: product }, {}, false);
this.barcodeInput.el.value = "";
}
} else {
this.env.services.notification.add("Product not found for barcode: " + barcode, { type: "danger" });
}
}
}
},
});
 My Backend Code:
from odoo import models

class PosConfig(models.Model):
_inherit = 'pos.config'

def _get_pos_ui_product_fields(self):
fields = super()._get_pos_ui_product_fields()
if 'allow_negative_pos_sale' not in fields:
fields.append('allow_negative_pos_sale')
print(f"[DEBUG] Barcode Search - POS UI Product fields: {fields}")

# Force ensure the field is loaded
if 'allow_negative_pos_sale' not in fields:
fields.append('allow_negative_pos_sale')
print(f"[DEBUG] Barcode Search - Force added allow_negative_pos_sale to POS UI fields")

return fields

def _loader_params_product_product(self):
res = super()._loader_params_product_product()
if 'allow_negative_pos_sale' not in res['search_params']['fields']:
res['search_params']['fields'].append('allow_negative_pos_sale')
print(f"[DEBUG] Barcode Search - Product fields being loaded: {res['search_params']['fields']}")

# Force ensure the field is loaded
if 'allow_negative_pos_sale' not in res['search_params']['fields']:
res['search_params']['fields'].append('allow_negative_pos_sale')
print(f"[DEBUG] Barcode Search - Force added allow_negative_pos_sale field")

# Also ensure we have the basic fields
required_fields = ['id', 'name', 'barcode', 'type', 'allow_negative_pos_sale']
for field in required_fields:
if field not in res['search_params']['fields']:
res['search_params']['fields'].append(field)
print(f"[DEBUG] Barcode Search - Force added required field: {field}")

# Also ensure we have the search domain
if 'search_params' not in res:
res['search_params'] = {}
if 'domain' not in res['search_params']:
res['search_params']['domain'] = []

return res

def _loader_params_product_template(self):
res = super()._loader_params_product_template()
if 'allow_negative_pos_sale' not in res['search_params']['fields']:
res['search_params']['fields'].append('allow_negative_pos_sale')
print(f"[DEBUG] Barcode Search - Product Template fields being loaded: {res['search_params']['fields']}")

# Force ensure the field is loaded
if 'allow_negative_pos_sale' not in res['search_params']['fields']:
res['search_params']['fields'].append('allow_negative_pos_sale')
print(f"[DEBUG] Barcode Search - Force added allow_negative_pos_sale to Product Template fields")

# Also ensure we have the basic fields
required_fields = ['id', 'name', 'type', 'allow_negative_pos_sale']
for field in required_fields:
if field not in res['search_params']['fields']:
res['search_params']['fields'].append(field)
print(f"[DEBUG] Barcode Search - Force added required field to Product Template: {field}")

return res

def _pos_ui_models_to_load(self):
res = super()._pos_ui_models_to_load()
if 'product.product' not in res:
res.append('product.product')
print(f"[DEBUG] Barcode Search - POS UI Models to load: {res}")

# Force ensure product.product is loaded
if 'product.product' not in res:
res.append('product.product')
print(f"[DEBUG] Barcode Search - Force added product.product to POS UI Models")

# Also ensure we have the basic models
required_models = ['product.product', 'product.template']
for model in required_models:
if model not in res:
res.append(model)
print(f"[DEBUG] Barcode Search - Force added required model: {model}")

return res

My Requirement:

I need a best hybrid logic:

  • If online → use server (dynamic data)
  • If offline → use local POS data (no RPC calls)
  • Barcode search should work in both cases

Can anyone help me modify this code to:

  • Work correctly in offline mode
  • Keep my existing online functionality
  • Ensure stock and barcode search works properly offline

Thanks in advance!



0
Avatar
Zrušit
Enjoying the discussion? Don't just read, join in!

Create an account today to enjoy exclusive features and engage with our awesome community!

Přihlásit se
Related Posts Odpovědi Zobrazení Aktivita
Is there any event after and event before functionality openerp 7
server pos
Avatar
0
bře 15
539
Settings Page can't be accessed - RPC_ERROR Odoo Server Error
server rpc errors
Avatar
Avatar
1
pro 22
5367
RPC_ERROR: ValueError: Invalid field 'brand_id' on model 'product.template' after "changing something""
server error rpc
Avatar
0
pro 22
7641
How to access sale.order.line objects from javascript when calling sale.order with a rpc call ?
pos sale.order.line rpc
Avatar
0
úno 21
4585
I can't send tickets by email at the point of sale, odoo 13 community
server pos email log
Avatar
0
bře 24
2643
Komunita
  • Tutoriály
  • Dokumentace
  • Fórum
Open Source
  • Stáhnout
  • Github
  • Runbot
  • Překlady
Služby
  • Odoo.sh hostování
  • Podpora
  • Upgrade
  • Nestandardní vývoj
  • Edukační program
  • Najít účetní
  • Najít partnera
  • Stát se partnerem
O nás
  • Naše společnost
  • Podklady značky
  • Kontakujte nás
  • Práce
  • Události
  • Podcast
  • Blog
  • Zákazníci
  • Právní dokumenty • Soukromí
  • Zabezpečení
الْعَرَبيّة Català 简体中文 繁體中文 (台灣) Čeština Dansk Nederlands English Suomi Français Deutsch हिंदी Bahasa Indonesia Italiano 日本語 한국어 (KR) Lietuvių kalba Język polski Português (BR) română русский язык Slovenský jazyk Slovenščina Español (América Latina) Español Svenska ภาษาไทย Türkçe українська Tiếng Việt

Odoo je balíček open-source aplikací, které pokrývají všechny potřeby vaší společnosti: CRM, e-shop, účetnictví, sklady, kasy, projektové řízení a další.

Unikátní nabídka od Odoo poskytuje velmi jednoduché uživatelské rozhraní a vše je integrované na jednom místě.

Website made with

Odoo Experience on YouTube

1. Use the live chat to ask your questions.
2. The operator answers within a few minutes.

Live support on Youtube
Watch now