Implementasi QR Code di Odoo dengan Aplikasi Mobile dan Tanpa Aplikasi Mobile (PWA)

Penggunaan QR Code semakin hari semakin populer dengan kemudahan dan kecepatannya. Sehingga banyak perusahaan menggunakan QR code dalam mempercepat proses bisnis.

Saya akan membagikan pengalaman implementasi odoo dengan APlikasi Android dan iOS maupun implementasi QR Code di Odoo tanpa aplikasi atau menggunakan PWA

1. Implementasi QR Code Odoo Dengan Aplikasi Mobile

Implementasi Odoo QR Code dengan Aplikasi merupakan implementasi yang menggunakan Android atau iOS untuk menangkap kode QR Code yang kemudian digunakan untuk memproses data yang ada di Odoo menggunakan API.

Dalam case ini saya akan memberikan contoh penggunaan QR Code di Flutter untuk bahasanya menggunakan bahasa Dart.

Dalam contoh ini QR Code digunakan untuk sistem patroli yang mencatat titik lokasi yang ditempel QR Code yang sudah disetting sebelumnya. Hasil dari tangkapan QR Code akan dikirim ke server Odoo dengan tujuan menandakan bahwa titik patroli tersebut sudah dilakukan patroli pada jam tersebut.

Tampilannya seperti ini :

QR Code Odoo dengan Flutter

Kelebihan versi Aplikasi Mobile bisa diberikan fitur menyalakan lampu flash untuk jaga-jaga jika di lokasi tidak terdapat penerangan yang cukup.

Kelebihan lain dari QR Code versi Aplikasi juga lebih stabil dalam mendeteksi QR Code.

Kekurangan dari versi Aplikasi adalah diperlukan resource lebih untuk melakukan perawatan kode sumber karena harus merawat 2 kode sumber yaitu kode di modul Odoo dan kode di Flutter.

Berikut ini kode Flutter yang saya gunakan untuk implementasi QR Code Odoo dengan Flutter :

class QRScanPage extends StatefulWidget {
  final int checkPointReportId;
  final int patrolReportId;
  final String code;
  final String json_question;
  final OdooClient odooClient;
  final String jadwalName;
  final int jadwalId;
  final int checkPointId;
  final String checkPointName;

  QRScanPage(
      {required this.checkPointReportId,
      required this.patrolReportId,
      required this.code,
      required this.json_question,
      required this.odooClient,
      required this.jadwalName,
      required this.jadwalId,
      required this.checkPointId,
      required this.checkPointName});

  @override
  _QRScanPageState createState() => _QRScanPageState();
}

class _QRScanPageState extends State<QRScanPage> {
  final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
  Barcode? result;
  QRViewController? controller;
  bool isFlashOn = false;

  @override
  void reassemble() {
    super.reassemble();
    controller?.pauseCamera();
    controller?.resumeCamera();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Arahkan kamera ke QR Code'),
        backgroundColor: const Color.fromARGB(255, 207, 33, 40),
        foregroundColor: Colors.white,
        leading: IconButton(
          icon: Icon(Icons.arrow_back),
          onPressed: () {
            Navigator.pushReplacement(
              context,
              MaterialPageRoute(
                builder: (context) => PatrolQRListPage(
                  odooClient: widget.odooClient,
                  jadwalName: widget.jadwalName,
                  patrolReportId: widget.patrolReportId,
                ),
              ),
            );
          },
        ),
      ),
      body: Stack(
        children: <Widget>[
          // QR Scanner
          QRView(
            key: qrKey,
            onQRViewCreated: _onQRViewCreated,
          ),
          // Overlay untuk area luar kotak yang gelap total
          Positioned.fill(
            child: ClipPath(
              // clipper: QRScannerOverlay(screenHeight: screenHeight),
              child: Container(
                color:
                    Colors.black.withOpacity(0), // Gelap total di luar kotak
              ),
            ),
          ),
          // Kotak dengan border putih di sudut-sudut
          Align(
            alignment: Alignment(0, -0.3),
            child: Container(
              width: 300,
              height: 300,
              decoration: BoxDecoration(
                border: Border.all(
                  color: const Color.fromARGB(
                      0, 255, 255, 255), // Warna border putih
                  width: 0,
                ),
              ),
              child: Stack(
                children: [
                  Positioned(
                    top: 0,
                    left: 0,
                    child: Container(
                      width: 40,
                      height: 40,
                      decoration: BoxDecoration(
                        border: Border(
                          top: BorderSide(color: Colors.white, width: 4),
                          left: BorderSide(color: Colors.white, width: 4),
                        ),
                      ),
                    ),
                  ),
                  Positioned(
                    top: 0,
                    right: 0,
                    child: Container(
                      width: 40,
                      height: 40,
                      decoration: BoxDecoration(
                        border: Border(
                          top: BorderSide(color: Colors.white, width: 4),
                          right: BorderSide(color: Colors.white, width: 4),
                        ),
                      ),
                    ),
                  ),
                  Positioned(
                    bottom: 0,
                    left: 0,
                    child: Container(
                      width: 40,
                      height: 40,
                      decoration: BoxDecoration(
                        border: Border(
                          bottom: BorderSide(color: Colors.white, width: 4),
                          left: BorderSide(color: Colors.white, width: 4),
                        ),
                      ),
                    ),
                  ),
                  Positioned(
                    bottom: 0,
                    right: 0,
                    child: Container(
                      width: 40,
                      height: 40,
                      decoration: BoxDecoration(
                        border: Border(
                          bottom: BorderSide(color: Colors.white, width: 4),
                          right: BorderSide(color: Colors.white, width: 4),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
          // Icon flashlight di pojok kanan atas
          Positioned(
            top: 20,
            right: 20,
            child: IconButton(
              icon: Icon(isFlashOn ? Icons.flash_on : Icons.flash_off,
                  color: Colors.white),
              onPressed: () async {
                await controller?.toggleFlash();
                setState(() {
                  isFlashOn = !isFlashOn;
                });
              },
            ),
          ),
          // Teks di bagian bawah
          Positioned(
            bottom: 0,
            left: 0,
            right: 0,
            child: Container(
              color: Colors.white,
              padding: EdgeInsets.all(50),
              child: Text(
                widget.checkPointName,
                style: TextStyle(
                  fontSize: 18,
                  color: Colors.black,
                  fontWeight: FontWeight.bold,
                ),
                textAlign: TextAlign.center,
              ),
            ),
          ),
        ],
      ),
    );
  }

  void _onQRViewCreated(QRViewController controller) {
    this.controller = controller;
    controller.scannedDataStream.listen((scanData) async {
      setState(() {
        result = scanData;
      });

      if (result != null) {
        if (result!.code != widget.code) {
          // jika qr code tidak sesuai dengan qr code yang ditentukan
          controller.pauseCamera();
          showErrorDialog(context, 'QR Code tidak valid..!');
        } else {
          // pause kamera
          controller.pauseCamera();
          // munculkan form survey
          final survey = Survey.fromJson(jsonDecode(widget.json_question));

          await Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => SurveyForm(
                      survey: survey,
                      odooClient: widget.odooClient,
                      jadwalName: widget.jadwalName,
                      patrolReportId: widget.patrolReportId,
                      checkPointId: widget.checkPointId,
                      checkPointReportId: widget.checkPointReportId,
                    )),
          );
        }
      }
    });
  }

  @override
  void dispose() {
    controller?.dispose();
    super.dispose();
  }

  void showErrorDialog(BuildContext context, String message) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Error'),
          content: Text(message),
          actions: <Widget>[
            TextButton(
              child: Text('OK'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }
}

2. Implementasi Odoo dengan Qr Code tanpa Aplikasi Mobile (Menggunakan PWA dan Web)

Sebenernya kita juga bisa menggunakan web dari modul Odoo langsung tanpa menggunakan tambahan Aplikasi Mobile untuk menambahkan fitur QR Code di Odoo.

Kelebihan menggunakan web atau PWA adalah lebih mudah dalam pembuatan dan lebih mudah alam maintenance kode untuk kedepannya karena tidak perlu melakukan maintenance 2 kode sumber.

Kelebihan lain juga lebih praktis karena jaman sekarang hampir semua broses mendukung install PWA

Tampilan dari QR Code versi PWA seperti ini

QR Code Odoo PWA

Librari yang saya pakai menggunakan html5-qrcode, dan seperti ini contoh kode untuk menggunakannya

var html5QrcodeScanner;
document.addEventListener("DOMContentLoaded", function() {
        const observer = new MutationObserver(function(mutations) {
            let elemen_qr = document.getElementById('qrdiv');

            let button_cancel = document.getElementsByClassName('o_form_button_cancel');
            console.dir(button_cancel);
            // disable camera untuk popup log dari ipm area
            if (button_cancel[1]){
                return;
            }

            let pestisida_0 = document.getElementById('pestisida_0');
            if (pestisida_0){
                elemen_qr.style.display = 'none';
                return;
            }

            let action_checkout = document.getElementsByName('action_checkout');
            if (action_checkout[0]){
                return;
            }

            let elemen_reader = document.getElementById('reader__scan_region');
            if (elemen_reader){
                return;
            }

            if (elemen_qr) {
                if (elemen_qr.style.display == 'none'){
                    console.log('3');
                    console.dir(elemen_qr);
                    return;
                }
                html5QrcodeScanner = new Html5QrcodeScanner("reader", { fps: 10, qrbox: 150 });
                html5QrcodeScanner.render(onScanSuccess);
            } else {
                console.log('tidak ada');
            }
		});
        observer.observe(document.body, {
            childList: true,
            attributes: true,
            subtree: true
        });
});

Kekurangan dari versi PWA adalah performance dan fitur yang tidak sebaik versi Aplikasi Mobile.

Baik versi APlikasi maupun versi PWA memiliki kelebihan dan kekurangan masing-masing, teman-teman bebas menentukan versi mana yang dipilih dan bisa juga kedua versi dipasang bersamaan.

Catatan : Versi Odoo 17

Leave a Comment

Your email address will not be published. Required fields are marked *

1