Integrasi Odoo dengan aplikasi mobile semakin banyak diminati perusahaan untuk semakin membuat proses bisnis semakin efisien dan kemudahan dalam operasional.
Kali ini saya kan memberikan contoh integrasi Odoo dengan aplikasi mobile Android dan iOS yang kami bangun menggunakan Flutter.
Aplikasi ini merupakan permintaan dari salah satu customer kami yang menggunakan Odoo untuk sistem patroli dan menggunakan modul survey untuk mencatat hasil patroli termasuk mengupload photo dan juga untuk mencatat lokasi (latitude dan longitude).
Di artikel ini saya akan membagikan beberapa kode Flutter yang bisa menginspirasi teman-teman yang mungkin sedang mengerjakan proyek serupa.
Hasil akhir dari aplikasi mobilenya seperti ini :
Aplikasi mobile tersebut mengambil data dati modul survey yang ada di Odoo dan menampilkan secara native di aplikasi mobile. Form yang ada di Odoo yang seperti ini :
Form yang ada di modul survey Odoo akan diisi melalui aplikasi mobile dan hasilnya menjadi seperti ini
Termasuk juga modifikasi module Odoo supaya bisa menerima upload photo dari aplikasi mobile dan menampilkannya di web. Hasilnya seperti ini :
Dalam case ini juga diperlukan titik lokasi patroli yang berupa latitude dan longitude yang dikirim oleh aplikasi ke Odoo
Code untuk mengirim latitude dan longitude dari Flutter ke Odoo sebagai berikut
// Dapatkan lokasi pengguna
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
Dan berikut ini adalah code untuk mengkonversi form survey yang ada di modul Odoo ke aplikasi Android dan iOS dengan Flutter
// Model untuk Question
class Question {
final int id;
final String title;
final String type;
final bool is_patrol_note;
final bool is_mandatory;
final List<Answer> answers;
Question({
required this.id,
required this.title,
required this.type,
required this.is_patrol_note,
required this.is_mandatory,
required this.answers,
});
factory Question.fromJson(Map<String, dynamic> json) {
var answersList = json['answers'] as List;
List<Answer> _answers =
answersList.map((answer) => Answer.fromJson(answer)).toList();
return Question(
id: json['id'],
title: json['title'],
type: json['type'],
is_patrol_note: json['is_patrol_note'],
is_mandatory: json['is_mandatory'],
answers: _answers,
);
}
}
// Model untuk Survey
class Survey {
final int id;
final String title;
final List<Question> questions;
Survey({required this.id, required this.title, required this.questions});
factory Survey.fromJson(Map<String, dynamic> json) {
var questionsList = json['questions'] as List;
List<Question> _questions =
questionsList.map((question) => Question.fromJson(question)).toList();
return Survey(
id: json['id'],
title: json['title'],
questions: _questions,
);
}
}
// Widget untuk Form Survey
class SurveyForm extends StatefulWidget {
final Survey survey;
final OdooClient odooClient;
final String jadwalName;
final int patrolReportId;
final int checkPointId;
final int checkPointReportId;
SurveyForm(
{required this.survey,
required this.odooClient,
required this.jadwalName,
required this.patrolReportId,
required this.checkPointId,
required this.checkPointReportId});
@override
_SurveyFormState createState() => _SurveyFormState();
}
Dan berikut ini adalah kelas untuk membuat tampilan questionnya
Widget buildQuestionWidget(Question question) {
switch (question.type) {
case 'simple_choice':
return buildSimpleChoiceQuestion(question);
case 'char_box':
return buildCharBoxQuestion(question);
case 'numerical_box':
return buildNumericalBoxQuestion(question);
default:
return Container();
}
}
Widget buildSimpleChoiceQuestion(Question question) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
question.title,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
Column(
children: question.answers.map((answer) {
return Column(
children: [
RadioListTile<int>(
title: Text(answer.value),
value: answer.id,
groupValue: answers[question.id],
onChanged: (value) {
setState(() {
answers[question.id] = value;
photo_required[question.id] = answer.photo_required;
});
},
),
if (answer.photo_required == true &&
photo_required[question.id] == true)
Column(
children: [
ElevatedButton(
onPressed: () => _pickImage(question.id),
child: Text('Upload Foto'),
),
if (images[question.id] != null)
GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius
.zero, // Menghilangkan rounded corners
),
child: Container(
width: 400,
child: Image.memory(
base64Decode(images[question.id]!),
fit: BoxFit.contain,
),
),
);
},
);
},
child: Image.memory(
base64Decode(images[question.id]!),
width: 40,
height: 40,
),
),
],
),
],
);
}).toList(),
),
],
);
}
Widget buildCharBoxQuestion(Question question) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
question.title,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
TextField(
onChanged: (value) {
answers[question.id] = value;
},
decoration: InputDecoration(
hintText: 'Masukkan teks',
),
),
],
);
}
Widget buildNumericalBoxQuestion(Question question) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
question.title,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
TextField(
keyboardType: TextInputType.number,
onChanged: (value) {
answers[question.id] = int.tryParse(value);
},
decoration: InputDecoration(
hintText: 'Masukkan angka',
),
),
],
);
}
Catatan : Odoo yang dipakai versi 17 dengan Flutter versi 3.24.2