diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 77fb674..14fe857 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,8 +22,8 @@ android { applicationId = "com.example.quiz" minSdk = 29 targetSdk = 34 - versionCode = 1 - versionName = "1.0" + versionCode = 2 + versionName = "1.1" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/example/quiz/AnnulationTicket.java b/app/src/main/java/com/example/quiz/AnnulationTicket.java index 34bfb9d..73525c6 100644 --- a/app/src/main/java/com/example/quiz/AnnulationTicket.java +++ b/app/src/main/java/com/example/quiz/AnnulationTicket.java @@ -102,6 +102,7 @@ public class AnnulationTicket extends Fragment { } case ERROR:{ MessageDialog.showError(getContext(), parisResponseResult.message); + dialog.dismiss(); break; } case SUCCESS:{ @@ -131,7 +132,8 @@ public class AnnulationTicket extends Fragment { dialog.dismiss(); }) .setPositiveButton("Confirmer", (annulationDialog, which) -> { - viewModel.annulerPari(ticketReference).observe(getViewLifecycleOwner(), new Observer>() { + String agentId = prefsHelper.get("id"); + viewModel.annulerPari(ticketReference, agentId).observe(getViewLifecycleOwner(), new Observer>() { @Override public void onChanged(Result pariResult) { switch (pariResult.status){ diff --git a/app/src/main/java/com/example/quiz/ApiUrlConfiguration.java b/app/src/main/java/com/example/quiz/ApiUrlConfiguration.java new file mode 100644 index 0000000..a6a81a1 --- /dev/null +++ b/app/src/main/java/com/example/quiz/ApiUrlConfiguration.java @@ -0,0 +1,93 @@ +package com.example.quiz; + +import android.content.SharedPreferences; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.example.quiz.databinding.FragmentApiUrlConfigurationBinding; +import com.example.quiz.utils.MessageDialog; +import com.example.quiz.utils.SharedPrefsHelper; + +/** + * A simple {@link Fragment} subclass. + * Use the {@link ApiUrlConfiguration#newInstance} factory method to + * create an instance of this fragment. + */ +public class ApiUrlConfiguration extends Fragment { + + private FragmentApiUrlConfigurationBinding binding; + + SharedPrefsHelper prefsHelper; + + // TODO: Rename parameter arguments, choose names that match + // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER + + public ApiUrlConfiguration() { + // Required empty public constructor + } + + // TODO: Rename and change types and number of parameters + public static ApiUrlConfiguration newInstance() { + ApiUrlConfiguration fragment = new ApiUrlConfiguration(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + prefsHelper = SharedPrefsHelper.getInstance(getContext()); + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + binding = FragmentApiUrlConfigurationBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + String serverLink = prefsHelper.get("MAIN_API_URL"); + String depLink = prefsHelper.get("REPORT_API_URL"); + if(serverLink!=null){ + binding.serverLink.setText(serverLink); + } + if(depLink!=null){ + binding.depLink.setText(depLink); + } + binding.btnValidate.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(binding.serverLink.getText().toString().isEmpty()){ + binding.serverLink.setError("Entrez l'URL du serveur"); + return; + } + if(binding.depLink.getText().toString().isEmpty()){ + binding.depLink.setError("Entrez l'URL de secours"); + return; + } + saveServerLinks(binding.serverLink.getText().toString(), binding.depLink.getText().toString()); + } + }); + super.onViewCreated(view, savedInstanceState); + } + + private void saveServerLinks(String serverLink, String depLink){ + SharedPreferences.Editor editor = prefsHelper.edit(); + editor.putString("MAIN_API_URL", serverLink); + editor.putString("REPORT_API_URL", depLink); + editor.apply(); + MessageDialog.showSuccess(getContext(), "URL's enregistrée avec succès"); + requireActivity().finishAffinity(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/quiz/BetValidation.java b/app/src/main/java/com/example/quiz/BetValidation.java index 921b668..4c2c2cc 100644 --- a/app/src/main/java/com/example/quiz/BetValidation.java +++ b/app/src/main/java/com/example/quiz/BetValidation.java @@ -343,6 +343,7 @@ public class BetValidation extends Fragment { } try { printPari(pariResult.data); + _initializeToZero(); dlg.dismiss(); prefsHelper.save("pariNoPrintId", null); } catch (WriterException e) { @@ -523,6 +524,7 @@ public class BetValidation extends Fragment { } try { printPari(pariResult.data); + _initializeToZero(); dlg.dismiss(); prefsHelper.save("pariNoPrintId", null); } catch (WriterException | FileNotFoundException e) { @@ -640,10 +642,8 @@ public class BetValidation extends Fragment { tspl.append(formattedDate).append("\n"); tspl.append("Course ").append(String.valueOf(pari.getCourseId())).append("\n"); tspl.append(sunmiPrinterManager.separationText()+ "\n"); - if(selectedHorses.getValue() == null){ - selectedHorses.setValue(Arrays.stream(pari.getCombinaison().split(",")).collect(Collectors.toList())); - } - int requireHorseNumber = shared != null && shared.typeOfBet != null? shared.typeOfBet.getValue().getNumberOfHorse():listProduits.get(pari.getTypesParisMises().get(0)); + selectedHorses.setValue(Arrays.stream(pari.getCombinaison().split(",")).collect(Collectors.toList())); + int requireHorseNumber = listProduits.get(pari.getTypesParisMises().get(0).getTypePari()); boolean isElargie = selectedHorses.getValue().size() > requireHorseNumber; String typePari = pari.getTypesParisMises().get(0).getTypePari(); tspl.append(isElargie ? typePari + "/Elargie" : typePari).append("\n"); @@ -652,7 +652,7 @@ public class BetValidation extends Fragment { tspl.append(combinationText).append("\n"); tspl.append("COEF: ").append(String.valueOf(pari.getCoefficient())); tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n"); - tspl.append("MONTANT: ").append(pari.getTypesParisMises().get(0).getMiseTotale()).append(" XOF"); + tspl.append("MONTANT: ").append( BitMapUtils.formatMontant(pari.getTypesParisMises().get(0).getMiseTotale())).append(" XOF"); tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n"); tspl.append("AGENT: ").append(prefsHelper.get("code")).append("\n"); tspl.append("DATE: ").append(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(OffsetDateTime.parse(pari.getDateHeurePrise()))).append("\n"); @@ -678,9 +678,7 @@ public class BetValidation extends Fragment { printPari(pari); dlg.dismiss(); prefsHelper.save("pariNoPrintId", null); - } catch (WriterException e) { - throw new RuntimeException(e); - } catch (FileNotFoundException e) { + } catch (WriterException | FileNotFoundException e) { throw new RuntimeException(e); } }) @@ -690,18 +688,19 @@ public class BetValidation extends Fragment { }); }else{ prefsHelper.save("pariNoPrintId", null); + binding.mise.setText("0 CFA"); } } }); - _initializeToZero(); return; } // MobiIotPrinterManager.getInstance().testImagePrinting(bitmap); - MobiIotPrinterManager.getInstance().printPari(BitMapUtils.bitmapToBmp(BitMapUtils.resizeToPrinterWidth(bitmap, 384)), BitMapUtils.bitmapToBmp(BitMapUtils.resizeToPrinterWidth(barcode, 384)), pari.getNumeroTicket(), tspl.toString(), new MobiIotPrinterManager.MobiIotPrinterStatus() { + MobiIotPrinterManager.getInstance().printPari(BitMapUtils.bitmapToBmp(BitMapUtils.resizeToPrinterWidth(bitmap, 384)), BitMapUtils.bitmapToBmp(BitMapUtils.resizeToPrinterWidth(barcode, 384)), pari.getNumeroTicket(), tspl, new MobiIotPrinterManager.MobiIotPrinterStatus() { @Override public void printStatusCode(int status) { + Log.e("TAG", "### "+String.valueOf(status)); if(status!=1){ prefsHelper.save("pariNoPrintId", String.valueOf(pari.getNumeroTicket())); new Handler(Looper.getMainLooper()).post(new Runnable() { @@ -738,7 +737,7 @@ public class BetValidation extends Fragment { @Override public void run() { prefsHelper.save("pariNoPrintId", null); - _initializeToZero(); + binding.mise.setText("0 CFA"); } }); } @@ -843,16 +842,16 @@ public class BetValidation extends Fragment { } } - } - try { - int printerStatus = MobiIotPrinterManager.getInstance().getPrinterStatus(); - Log.e("TAG", "### "+String.valueOf(printerStatus)); - if(printerStatus != 1){ - MessageDialog.showError(getContext(), "Erreur lors de l'impréssion."+"\n"+" Veuillez vérifier le papier puis rééssayer!"); - return; + }else{ + try { + int printerStatus = MobiIotPrinterManager.getInstance().getPrinterStatus(); + if(printerStatus != 1){ + MessageDialog.showError(getContext(), "Erreur lors de l'impréssion."+"\n"+" Veuillez vérifier le papier puis rééssayer!"); + return; + } + } catch (RemoteException e) { + throw new RuntimeException(e); } - } catch (RemoteException e) { - throw new RuntimeException(e); } pariViewModel.createPari(pari).observe(getViewLifecycleOwner(), new Observer>() { @Override @@ -862,14 +861,17 @@ public class BetValidation extends Fragment { loader.dismiss(); dialog.dismiss(); MessageDialog.showError(getContext(), pariResult.message); + view.findViewById(R.id.alert_validate).setEnabled(false); break; case LOADING: loader.show("Prise de pari"); + view.findViewById(R.id.alert_validate).setEnabled(false); break; case SUCCESS: try { loader.dismiss(); logsViewModel.insertLog(prefsHelper.get("id"), "BET", "Création du pari " + pariResult.data.getNumeroTicket() + ", type de paris: " + pariResult.data.getTypesParisMises().get(0).getTypePari() + ", combinaison:" + selectedHorses.getValue().stream().map(String::valueOf).collect(Collectors.joining("-")), System.currentTimeMillis()); + _initializeToZero(); printPari(pariResult.data); dialog.dismiss(); MessageDialog.showSuccess(getContext(), "Pari créé avec succès"); @@ -892,7 +894,7 @@ public class BetValidation extends Fragment { } void _initializeToZero() { - selectedHorses.setValue(List.of()); + selectedHorses.postValue(new ArrayList<>()); binding.combination.setText(""); binding.order.setChecked(false); order = false; diff --git a/app/src/main/java/com/example/quiz/Caisse.java b/app/src/main/java/com/example/quiz/Caisse.java index 7ddb123..6300454 100644 --- a/app/src/main/java/com/example/quiz/Caisse.java +++ b/app/src/main/java/com/example/quiz/Caisse.java @@ -88,6 +88,9 @@ public class Caisse extends Fragment { binding.lastBetsBtn.setOnClickListener(v -> { authNavigator.navigate(DerniersParis.newInstance()); }); + binding.raceReport.setOnClickListener(v -> { + authNavigator.navigate(RaceReport.newInstance()); + }); } @Override diff --git a/app/src/main/java/com/example/quiz/DerniersParis.java b/app/src/main/java/com/example/quiz/DerniersParis.java index d8c9ee8..640bf38 100644 --- a/app/src/main/java/com/example/quiz/DerniersParis.java +++ b/app/src/main/java/com/example/quiz/DerniersParis.java @@ -198,7 +198,8 @@ public class DerniersParis extends Fragment { } void _cancelPari(ParisResponse pari){ - viewModel.annulerPari(pari.getNumeroTicket()).observe(getViewLifecycleOwner(), new Observer>() { + String agentId = prefsHelper.get("id"); + viewModel.annulerPari(pari.getNumeroTicket(), agentId).observe(getViewLifecycleOwner(), new Observer>() { @Override public void onChanged(Result result) { switch (result.status){ @@ -313,7 +314,7 @@ public class DerniersParis extends Fragment { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); String formattedDate = dateTime.format(formatter); tspl.append(formattedDate).append("\n"); - tspl.append("Course ").append(String.valueOf(pari.getCourseId())).append("\n"); + tspl.append("Course ").append(BitMapUtils.formatMontant(pari.getCourseId())).append("\n"); tspl.append(sunmiPrinterManager.separationText()+"\n"); List selectedHorses = Arrays.stream(pari.getCombinaison().split(",")).collect(Collectors.toList()); boolean isElargie = selectedHorses.size()> listProduits.get(pari.getTypesParisMises().get(0).getTypePari()); @@ -322,9 +323,9 @@ public class DerniersParis extends Fragment { tspl.append(pari.getFormules().contains("FORMULE_COMPLETE") ?"COMBINAISON COMPLETE"+"\n":""); String combinationText = BitMapUtils.formatLineWithNumbers(selectedHorses.stream().map(String::valueOf).toArray(String[]::new), "-", listProduits.get(pari.getTypesParisMises().get(0).getTypePari())); tspl.append(combinationText).append("\n"); - tspl.append("COEF: ").append(String.valueOf(pari.getCoefficient())); + tspl.append("COEF: ").append(BitMapUtils.formatMontant(pari.getCoefficient())); tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n"); - tspl.append("MONTANT: ").append(pari.getMiseTotale()).append(" XOF"); + tspl.append("MONTANT: ").append(BitMapUtils.formatMontant(pari.getMiseTotale())).append(" XOF"); tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n"); tspl.append("AGENT: ").append(pari.getAgentCode()).append("\n"); tspl.append("DATE: ").append(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(OffsetDateTime.parse(pari.getDateHeurePrise()))).append("\n"); @@ -348,7 +349,7 @@ public class DerniersParis extends Fragment { }); return; } - MobiIotPrinterManager.getInstance().printPari(BitMapUtils.bitmapToBmp(BitMapUtils.resizeToPrinterWidth(bitmap, 384)), BitMapUtils.bitmapToBmp(barcode), pari.getNumeroTicket(), tspl.toString(), new MobiIotPrinterManager.MobiIotPrinterStatus() { + MobiIotPrinterManager.getInstance().printPari(BitMapUtils.bitmapToBmp(BitMapUtils.resizeToPrinterWidth(bitmap, 384)), BitMapUtils.bitmapToBmp(barcode), pari.getNumeroTicket(), tspl, new MobiIotPrinterManager.MobiIotPrinterStatus() { @Override public void printStatusCode(int status) { if(status != 1){ diff --git a/app/src/main/java/com/example/quiz/Login.java b/app/src/main/java/com/example/quiz/Login.java index f4a396e..5f0841b 100644 --- a/app/src/main/java/com/example/quiz/Login.java +++ b/app/src/main/java/com/example/quiz/Login.java @@ -11,9 +11,11 @@ import androidx.lifecycle.ViewModelProvider; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; import com.example.quiz.databinding.FragmentLoginBinding; import com.example.quiz.utils.AuthNavigator; +import com.example.quiz.utils.MessageDialog; import com.example.quiz.utils.SessionManager; import com.example.quiz.utils.SharedPrefsHelper; import com.example.quiz.viewModel.LoginViewModel; @@ -31,6 +33,10 @@ public class Login extends Fragment { private AuthNavigator authNavigator; + private int clickCount = 0; + private long lastClickTime = 0; + private static final int CLICKS_REQUIRED = 5; + private static final long TIME_WINDOW = 2000; private SharedPrefsHelper prefsHelper; public Login() { // Required empty public constructor @@ -62,13 +68,33 @@ public class Login extends Fragment { @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - SessionManager sessionManager = SessionManager.newInstance(getContext()); - FragmentManager fragmentManager = getParentFragmentManager(); AppCompatActivity activity = (AppCompatActivity) getActivity(); if(activity != null){ activity.getSupportActionBar().hide(); } + binding.icon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + long currentTime = System.currentTimeMillis(); + if (currentTime - lastClickTime > TIME_WINDOW) { + clickCount = 0; + } else { + clickCount++; + } + lastClickTime = currentTime; + if(clickCount == CLICKS_REQUIRED){ + clickCount = 0; + ApiUrlConfiguration apiUrlConfiguration = ApiUrlConfiguration.newInstance(); + FragmentManager fragmentManager = getParentFragmentManager(); + fragmentManager.beginTransaction() + .replace(R.id.nav_host_fragment_content_main, apiUrlConfiguration) + .addToBackStack(null) + .commit(); + } + } + }); + } public void onStart(){ diff --git a/app/src/main/java/com/example/quiz/PageQuiz.java b/app/src/main/java/com/example/quiz/PageQuiz.java index 2d405ee..b54bcee 100644 --- a/app/src/main/java/com/example/quiz/PageQuiz.java +++ b/app/src/main/java/com/example/quiz/PageQuiz.java @@ -62,6 +62,7 @@ public class PageQuiz extends AppCompatActivity { super.onCreate(savedInstanceState); exemptedFragment.add(ServerConfig.class); exemptedFragment.add(Logs.class); + exemptedFragment.add(ApiUrlConfiguration.class); sessionManager = SessionManager.newInstance(this); mobileName = Build.MANUFACTURER; binding = ActivityPageQuizBinding.inflate(getLayoutInflater()); diff --git a/app/src/main/java/com/example/quiz/RaceReport.java b/app/src/main/java/com/example/quiz/RaceReport.java new file mode 100644 index 0000000..ad575fd --- /dev/null +++ b/app/src/main/java/com/example/quiz/RaceReport.java @@ -0,0 +1,231 @@ +package com.example.quiz; + +import android.app.AlertDialog; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; + +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.example.quiz.data.model.enums.TypeProduits; +import com.example.quiz.databinding.FragmentRaceReportBinding; +import com.example.quiz.utils.BitMapUtils; +import com.example.quiz.utils.LoaderDialog; +import com.example.quiz.utils.MessageDialog; +import com.example.quiz.utils.MobiIotPrinterManager; +import com.example.quiz.utils.Result; +import com.example.quiz.utils.SunmiPrinterManager; +import com.example.quiz.viewModel.RapportCourseViewModel; + +import dagger.hilt.android.AndroidEntryPoint; + +/** + * A simple {@link Fragment} subclass. + * Use the {@link RaceReport#newInstance} factory method to + * create an instance of this fragment. + */ +@AndroidEntryPoint +public class RaceReport extends Fragment { + + FragmentRaceReportBinding binding; + + SunmiPrinterManager sunmiPrinterManager; + + String mobileName; + + MutableLiveData isPrinterReady = new MutableLiveData<>(false); + + LoaderDialog loader; + + RapportCourseViewModel rapportCourseViewModel; + + + public RaceReport() { + // Required empty public constructor + } + + // TODO: Rename and change types and number of parameters + public static RaceReport newInstance() { + RaceReport fragment = new RaceReport(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + rapportCourseViewModel = new ViewModelProvider(this).get(RapportCourseViewModel.class); + loader = new LoaderDialog(getContext()); + mobileName = Build.MANUFACTURER; + sunmiPrinterManager = SunmiPrinterManager.getInstance(requireContext()); + if(mobileName.toLowerCase().contains("sunmi")){ + sunmiPrinterManager.connectPrinter(status -> { + isPrinterReady.setValue(status); + sunmiPrinterManager.disableSystemMessages(); + }); + }else{ + MobiIotPrinterManager.getInstance().init(requireContext()); + } + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + binding = FragmentRaceReportBinding.inflate(inflater, container, false); + // Inflate the layout for this fragment + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + binding.btnCheckBalance.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(binding.etRaceNumber.getText().toString().isEmpty()){ + binding.etRaceNumber.setError("Veuillez entrer un numéro de course"); + return; + } + rapportCourseViewModel.getRaceReport(binding.etRaceNumber.getText().toString()).observe(getViewLifecycleOwner(), new Observer>() { + @Override + public void onChanged(Result raceReportResult) { + switch (raceReportResult.status){ + case LOADING:{ + loader.show("Chargement du rapport"); + break; + } + case ERROR:{ + loader.dismiss(); + MessageDialog.showError(getContext(), raceReportResult.message); + break; + } + case SUCCESS:{ + loader.dismiss(); + new AlertDialog.Builder(getContext()).setTitle("Rapport") + .setMessage("Voulez-vous imprimer le rapport ?") + .setPositiveButton("Oui", (dialog, which) -> { + try { + printRapport(raceReportResult.data); + dialog.dismiss(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + }) + .setNegativeButton("Non", (dialog, which) -> { + dialog.dismiss(); + }).show(); + break; + } + } + } + }); + } + }); + } + + void printRapport(com.example.quiz.data.model.RaceReport report) throws RemoteException { + Bitmap logo = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo); + String courseCode = report.getCodeCourse()+" "+report.getDateCourse(); + String hippodomeName = report.getHippodrome(); + String courseName = report.getNomCourse() != null?report.getNomCourse().toUpperCase():"Non défini"; + String arrivee = report.getArrivee(); + String nonPartants = !report.getNonPartants().equals("néant".toUpperCase())?report.getNonPartants():" "; + StringBuilder text = new StringBuilder(); + if(report.getDetailsGagnantsGroupes().get(TypeProduits.QUINTE) != null && report.getDetailsGagnantsGroupes().get(TypeProduits.QUINTE).size() > 0){ + text.append("Quinté+").append("\n"); + report.getDetailsGagnantsGroupes().get(TypeProduits.QUINTE).forEach((item)->{ + text.append(item.getLibelle()).append(" : ").append(BitMapUtils.formatMontant(item.getMassePayee())).append(" XOF").append("\n"); + }); + text.append("\n"); + } + if(report.getDetailsGagnantsGroupes().get(TypeProduits.QUARTE) != null && report.getDetailsGagnantsGroupes().get(TypeProduits.QUARTE).size() > 0){ + text.append("Quarté").append("\n"); + report.getDetailsGagnantsGroupes().get(TypeProduits.QUARTE).forEach((item)->{ + text.append(item.getLibelle()+" : ").append(BitMapUtils.formatMontant(item.getMassePayee())).append(" XOF").append("\n"); + }); + text.append("\n"); + } + if(report.getDetailsGagnantsGroupes().get(TypeProduits.TIERCE) != null && report.getDetailsGagnantsGroupes().get(TypeProduits.TIERCE).size() > 0){ + text.append("Tiercé").append("\n"); + report.getDetailsGagnantsGroupes().get(TypeProduits.TIERCE).forEach((item)->{ + text.append(item.getLibelle()+" : ").append(BitMapUtils.formatMontant(item.getMassePayee())).append(" XOF").append("\n"); + }); + text.append("\n"); + } + if(report.getDetailsGagnantsGroupes().get(TypeProduits.COUPLE_GAGNANT) != null && report.getDetailsGagnantsGroupes().get(TypeProduits.COUPLE_GAGNANT).size() > 0){ + text.append("Couplé gagnant").append("\n"); + report.getDetailsGagnantsGroupes().get(TypeProduits.COUPLE_GAGNANT).forEach((item)->{ + text.append(item.getLibelle()+" : ").append(BitMapUtils.formatMontant(item.getMassePayee())).append(" XOF").append("\n"); + }); + text.append("\n"); + } + if(report.getDetailsGagnantsGroupes().get(TypeProduits.COUPLE_PLACE) != null && report.getDetailsGagnantsGroupes().get(TypeProduits.COUPLE_PLACE).size() > 0){ + text.append("Couplé placé").append("\n"); + report.getDetailsGagnantsGroupes().get(TypeProduits.COUPLE_PLACE).forEach((item)->{ + text.append(item.getLibelle()+" : ").append(BitMapUtils.formatMontant(item.getMassePayee())).append(" XOF").append("\n"); + }); + text.append("\n"); + } + if(mobileName.toLowerCase().contains("sunmi")){ + if(isPrinterReady.getValue() == null || !isPrinterReady.getValue()){ + sunmiPrinterManager.connectPrinter(status ->{ + isPrinterReady.setValue(status); + }); + } + if(sunmiPrinterManager.printerStatus() != 1){ + MessageDialog.showError(getContext(), "Erreur lors de l'impréssion, Veuillez rééssayer S.V.P!"); + return; + } + sunmiPrinterManager.printRapport(BitMapUtils.resizeToPrinterWidth(logo, 384), courseCode, hippodomeName, courseName, arrivee, nonPartants, text, new SunmiPrinterManager.PrintStatusListener() { + @Override + public void onStatusChanged(boolean status) { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + if(!status){ + MessageDialog.showError(getContext(), "Erreur lors de l'impréssion, Veuillez rééssayer S.V.P!"); + return; + } + MessageDialog.showSuccess(getContext(), "Rapport imprimé avec succès"); + } + }); + } + }); + }else{ + if(MobiIotPrinterManager.getInstance().getPrinterStatus() != 1){ + MessageDialog.showError(getContext(), "Erreur lors de l'impréssion, Veuillez rééssayer S.V.P!"); + return; + } + MobiIotPrinterManager.getInstance().printRapport(BitMapUtils.bitmapToBmp(BitMapUtils.resizeToPrinterWidth(logo, 384)), courseCode, hippodomeName, courseName, arrivee, nonPartants, text, new MobiIotPrinterManager.MobiIotPrinterStatus() { + @Override + public void printStatusCode(int status) { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + if(status == 1 ){ + MessageDialog.showSuccess(getContext(), "Rapport imprimé avec succès"); + }else{ + MessageDialog.showError(getContext(), "Erreur lors de l'impréssion, Veuillez rééssayer S.V.P!"); + } + } + }); + + } + }); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/quiz/ServerConfig.java b/app/src/main/java/com/example/quiz/ServerConfig.java index 2c400f4..23844de 100644 --- a/app/src/main/java/com/example/quiz/ServerConfig.java +++ b/app/src/main/java/com/example/quiz/ServerConfig.java @@ -118,7 +118,8 @@ public class ServerConfig extends Fragment { case SUCCESS: loader.dismiss(); existingTpe = tpeResult.data; - if( existingTpe != null && Objects.equals(sharedPrefsHelper.get("terminalId"), String.valueOf(existingTpe.getId()))){ + String numeroSerie = Settings.Secure.getString(getContext().getContentResolver(), Settings.Secure.ANDROID_ID); + if(existingTpe != null && existingTpe.getNumeroSerie().equals(numeroSerie)){ _checkPdv(existingTpe); return; }else{ diff --git a/app/src/main/java/com/example/quiz/Sold.java b/app/src/main/java/com/example/quiz/Sold.java index 8cbad1f..db74e38 100644 --- a/app/src/main/java/com/example/quiz/Sold.java +++ b/app/src/main/java/com/example/quiz/Sold.java @@ -218,13 +218,13 @@ public class Sold extends Fragment { Bitmap logo = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo); String title = "SOLDE AU "+date; StringBuilder text = new StringBuilder(); - text.append("VENTES HIPPIQUES: ").append(String.valueOf(soldeResponse.getMontantParis())).append(" XOF").append("\n"); - text.append("NBR. PAIEMENTS: ").append(soldeResponse.getNombrePaiements()).append("\n"); - text.append("PAIEMENTS: ").append(String.valueOf(soldeResponse.getMontantPaiements())).append(" XOF").append("\n"); - text.append("NBR. ANNULATIONS: ").append(soldeResponse.getNombreAnnulations()).append("\n"); - text.append("ANNULATIONS: ").append(String.valueOf(soldeResponse.getMontantAnnulations())).append(" XOF").append("\n"); + text.append("VENTES HIPPIQUES: ").append(BitMapUtils.formatMontant(soldeResponse.getMontantParis())).append(" XOF").append("\n"); + text.append("NBR. PAIEMENTS: ").append(BitMapUtils.formatMontant(soldeResponse.getNombrePaiements())).append("\n"); + text.append("PAIEMENTS: ").append(BitMapUtils.formatMontant(soldeResponse.getMontantPaiements())).append(" XOF").append("\n"); + text.append("NBR. ANNULATIONS: ").append(BitMapUtils.formatMontant(soldeResponse.getNombreAnnulations())).append("\n"); + text.append("ANNULATIONS: ").append(BitMapUtils.formatMontant(soldeResponse.getMontantAnnulations())).append(" XOF").append("\n"); text.append(sunmiPrinterManager.separationText()).append("\n"); - text.append("SOLDE: ").append(String.valueOf(solde)).append(" XOF").append("\n"); + text.append("SOLDE: ").append(BitMapUtils.formatMontant(solde)).append(" XOF").append("\n"); text.append(sunmiPrinterManager.separationText()).append("\n"); text.append("AGENT : ").append(prefsHelper.get("code")).append("\n"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); diff --git a/app/src/main/java/com/example/quiz/SoldByCourse.java b/app/src/main/java/com/example/quiz/SoldByCourse.java index e4e45f8..a8c65bf 100644 --- a/app/src/main/java/com/example/quiz/SoldByCourse.java +++ b/app/src/main/java/com/example/quiz/SoldByCourse.java @@ -173,13 +173,13 @@ public class SoldByCourse extends Fragment { Bitmap logo = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo); String title = "SOLDE DE LA COURSE "+numero; StringBuilder text = new StringBuilder(); - text.append("VENTES HIPPIQUES: ").append(String.valueOf(soldeResponse.getMontantParis())).append(" XOF").append("\n"); - text.append("NBR. PAIEMENTS: ").append(soldeResponse.getNombrePaiements()).append("\n"); - text.append("PAIEMENTS: ").append(String.valueOf(soldeResponse.getMontantPaiements())).append(" XOF").append("\n"); - text.append("NBR. ANNULATIONS: ").append(soldeResponse.getNombreAnnulations()).append("\n"); - text.append("ANNULATIONS: ").append(String.valueOf(soldeResponse.getMontantAnnulations())).append(" XOF").append("\n"); + text.append("VENTES HIPPIQUES: ").append(BitMapUtils.formatMontant(soldeResponse.getMontantParis())).append(" XOF").append("\n"); + text.append("NBR. PAIEMENTS: ").append(BitMapUtils.formatMontant(soldeResponse.getNombrePaiements())).append("\n"); + text.append("PAIEMENTS: ").append(BitMapUtils.formatMontant(soldeResponse.getMontantPaiements())).append(" XOF").append("\n"); + text.append("NBR. ANNULATIONS: ").append(BitMapUtils.formatMontant(soldeResponse.getNombreAnnulations())).append("\n"); + text.append("ANNULATIONS: ").append(BitMapUtils.formatMontant(soldeResponse.getMontantAnnulations())).append(" XOF").append("\n"); text.append(sunmiPrinterManager.separationText()).append("\n"); - text.append("SOLDE: ").append(String.valueOf(solde)).append(" XOF").append("\n"); + text.append("SOLDE: ").append(BitMapUtils.formatMontant(solde)).append(" XOF").append("\n"); text.append(sunmiPrinterManager.separationText()).append("\n"); text.append("AGENT : ").append(prefsHelper.get("code")).append("\n"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); diff --git a/app/src/main/java/com/example/quiz/StompModule.java b/app/src/main/java/com/example/quiz/StompModule.java index a746606..157fee1 100644 --- a/app/src/main/java/com/example/quiz/StompModule.java +++ b/app/src/main/java/com/example/quiz/StompModule.java @@ -1,5 +1,7 @@ package com.example.quiz; +import android.content.Context; + import com.example.quiz.data.remote.NotificationHelper; import com.example.quiz.data.remote.StompManager; import com.example.quiz.data.remote.TokenManager; @@ -9,6 +11,7 @@ import javax.inject.Singleton; import dagger.Module; import dagger.Provides; import dagger.hilt.InstallIn; +import dagger.hilt.android.qualifiers.ApplicationContext; import dagger.hilt.components.SingletonComponent; @Module @@ -18,7 +21,7 @@ public class StompModule { @Provides @Singleton public StompManager provideStompManager(TokenManager tokenManager, - NotificationHelper notificationHelper) { - return new StompManager(tokenManager, notificationHelper); + NotificationHelper notificationHelper, @ApplicationContext Context context) { + return new StompManager(tokenManager, notificationHelper, context); } } \ No newline at end of file diff --git a/app/src/main/java/com/example/quiz/data/model/GainRapportProduit.java b/app/src/main/java/com/example/quiz/data/model/GainRapportProduit.java new file mode 100644 index 0000000..5171dd0 --- /dev/null +++ b/app/src/main/java/com/example/quiz/data/model/GainRapportProduit.java @@ -0,0 +1,47 @@ +package com.example.quiz.data.model; + +public class GainRapportProduit { + private String libelle; + private double nombre; + private double rapportUnitaire; + private double massePayee; + + public GainRapportProduit(String libelle, double nombre, double rapportUnitaire, double massePayee) { + this.libelle = libelle; + this.nombre = nombre; + this.rapportUnitaire = rapportUnitaire; + this.massePayee = massePayee; + } + + public String getLibelle() { + return libelle; + } + + public void setLibelle(String libelle) { + this.libelle = libelle; + } + + public double getNombre() { + return nombre; + } + + public void setNombre(double nombre) { + this.nombre = nombre; + } + + public double getRapportUnitaire() { + return rapportUnitaire; + } + + public void setRapportUnitaire(double rapportUnitaire) { + this.rapportUnitaire = rapportUnitaire; + } + + public double getMassePayee() { + return massePayee; + } + + public void setMassePayee(double massePayee) { + this.massePayee = massePayee; + } +} diff --git a/app/src/main/java/com/example/quiz/data/model/RaceReport.java b/app/src/main/java/com/example/quiz/data/model/RaceReport.java new file mode 100644 index 0000000..199cefa --- /dev/null +++ b/app/src/main/java/com/example/quiz/data/model/RaceReport.java @@ -0,0 +1,93 @@ +package com.example.quiz.data.model; + + +import com.example.quiz.data.model.enums.TypeProduits; + +import java.util.List; +import java.util.Map; + +public class RaceReport { + private String dateCourse; + private String hippodrome; + private String codeCourse; + private String nomCourse; + private int nbrePartants; + private String arrivee; + private String nonPartants; + private Map> detailsGagnantsGroupes; + + public RaceReport(String dateCourse, String hippodrome, String codeCourse, String nomCourse, int nbrePartants, String arrivee, String nonPartants, Map> detailsGagnantsGroupes) { + this.dateCourse = dateCourse; + this.hippodrome = hippodrome; + this.codeCourse = codeCourse; + this.nomCourse = nomCourse; + this.nbrePartants = nbrePartants; + this.arrivee = arrivee; + this.nonPartants = nonPartants; + this.detailsGagnantsGroupes = detailsGagnantsGroupes; + } + + public String getNomCourse() { + return nomCourse; + } + + public void setNomCourse(String nomCourse) { + this.nomCourse = nomCourse; + } + + public String getDateCourse() { + return dateCourse; + } + + public void setDateCourse(String dateCourse) { + this.dateCourse = dateCourse; + } + + public String getHippodrome() { + return hippodrome; + } + + public void setHippodrome(String hippodrome) { + this.hippodrome = hippodrome; + } + + public String getCodeCourse() { + return codeCourse; + } + + public void setCodeCourse(String codeCourse) { + this.codeCourse = codeCourse; + } + + public int getNbrePartants() { + return nbrePartants; + } + + public void setNbrePartants(int nbrePartants) { + this.nbrePartants = nbrePartants; + } + + public String getArrivee() { + return arrivee; + } + + public void setArrivee(String arrivee) { + this.arrivee = arrivee; + } + + public String getNonPartants() { + return nonPartants; + } + + public void setNonPartants(String nonPartants) { + this.nonPartants = nonPartants; + } + + public Map> getDetailsGagnantsGroupes() { + return detailsGagnantsGroupes; + } + + public void setDetailsGagnantsGroupes(Map> detailsGagnantsGroupes) { + this.detailsGagnantsGroupes = detailsGagnantsGroupes; + } +} diff --git a/app/src/main/java/com/example/quiz/data/model/enums/TypeProduits.java b/app/src/main/java/com/example/quiz/data/model/enums/TypeProduits.java new file mode 100644 index 0000000..7a4450e --- /dev/null +++ b/app/src/main/java/com/example/quiz/data/model/enums/TypeProduits.java @@ -0,0 +1,10 @@ +package com.example.quiz.data.model.enums; + +public enum TypeProduits { + QUINTE, + QUARTE, + TIERCE, + COUPLE_GAGNANT, + COUPLE_PLACE + +} diff --git a/app/src/main/java/com/example/quiz/data/remote/ApiClient.java b/app/src/main/java/com/example/quiz/data/remote/ApiClient.java index cab15eb..145c977 100644 --- a/app/src/main/java/com/example/quiz/data/remote/ApiClient.java +++ b/app/src/main/java/com/example/quiz/data/remote/ApiClient.java @@ -1,9 +1,12 @@ package com.example.quiz.data.remote; +import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; +import com.example.quiz.utils.SharedPrefsHelper; + import java.util.concurrent.TimeUnit; import javax.inject.Singleton; @@ -11,6 +14,7 @@ import javax.inject.Singleton; import dagger.Module; import dagger.Provides; import dagger.hilt.InstallIn; +import dagger.hilt.android.qualifiers.ApplicationContext; import dagger.hilt.components.SingletonComponent; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; @@ -20,8 +24,12 @@ import retrofit2.converter.gson.GsonConverterFactory; @Module @InstallIn(SingletonComponent.class) public class ApiClient { - private static final String BASE_URL = "https://alr.pmu.ml/api/"; + private static final String DEFAULT_BASE_URL = "https://api-alr.pmu.ml/api/"; + private static final String DEFAULT_REPORT_BASE_URL = "https://dep-alr.pmu.ml/api/v1/"; + + private static final String BASE_URL_KEY = "MAIN_API_URL"; + private static final String REPORT_BASE_URL_KEY = "REPORT_API_URL"; @Provides @Singleton @@ -55,7 +63,9 @@ public class ApiClient { @Provides @Singleton - public Retrofit provideRetrofit(OkHttpClient okHttpClient){ + public Retrofit provideRetrofit(OkHttpClient okHttpClient, @ApplicationContext Context context){ + SharedPrefsHelper prefsHelper = SharedPrefsHelper.getInstance(context); + String BASE_URL = prefsHelper.getString(BASE_URL_KEY, DEFAULT_BASE_URL); return new Retrofit.Builder() .baseUrl(BASE_URL) .client(okHttpClient) @@ -68,4 +78,23 @@ public class ApiClient { public ApiService provideApiService(Retrofit retrofit){ return retrofit.create(ApiService.class); } + + @Provides + @Singleton + @ReportApiClient + public Retrofit provideReportRetrofit(OkHttpClient okHttpClient, @ApplicationContext Context context){ + SharedPrefsHelper prefsHelper = SharedPrefsHelper.getInstance(context); + String REPORT_BASE_URL = prefsHelper.getString(REPORT_BASE_URL_KEY, DEFAULT_REPORT_BASE_URL); + return new Retrofit.Builder() + .baseUrl(REPORT_BASE_URL) + .client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + } + @Provides + @Singleton + public ReportApiService provideReportApiService(@ReportApiClient Retrofit retrofit){ + return retrofit.create(ReportApiService.class); + } + } diff --git a/app/src/main/java/com/example/quiz/data/remote/ApiService.java b/app/src/main/java/com/example/quiz/data/remote/ApiService.java index d0004f1..fac1d65 100644 --- a/app/src/main/java/com/example/quiz/data/remote/ApiService.java +++ b/app/src/main/java/com/example/quiz/data/remote/ApiService.java @@ -43,7 +43,7 @@ public interface ApiService { Call> derniersParis(@Path("agentId") String agentId); @PATCH("paris/numero/{numeroTicket}/cancel") - Call annulerPari(@Path("numeroTicket") String numeroTicket); + Call annulerPari(@Path("numeroTicket") String numeroTicket, @Query("agentId") String agentId); @PATCH("paris/numero/{numeroTicket}/rembourser") Call rembourserPari(@Path("numeroTicket") String numeroTicket); diff --git a/app/src/main/java/com/example/quiz/data/remote/ReportApiClient.java b/app/src/main/java/com/example/quiz/data/remote/ReportApiClient.java new file mode 100644 index 0000000..e037605 --- /dev/null +++ b/app/src/main/java/com/example/quiz/data/remote/ReportApiClient.java @@ -0,0 +1,9 @@ +package com.example.quiz.data.remote; + +import java.lang.annotation.RetentionPolicy; + +@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +@javax.inject.Qualifier +public @interface ReportApiClient{ + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/quiz/data/remote/ReportApiService.java b/app/src/main/java/com/example/quiz/data/remote/ReportApiService.java new file mode 100644 index 0000000..a09c379 --- /dev/null +++ b/app/src/main/java/com/example/quiz/data/remote/ReportApiService.java @@ -0,0 +1,12 @@ +package com.example.quiz.data.remote; + +import com.example.quiz.data.model.RaceReport; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Path; + +public interface ReportApiService { + @GET("rapports/course/{courseId}/fiche-calcul") + Call getRaceReport(@Path("courseId") String courseId); +} diff --git a/app/src/main/java/com/example/quiz/data/remote/StompManager.java b/app/src/main/java/com/example/quiz/data/remote/StompManager.java index e60095b..3f31795 100644 --- a/app/src/main/java/com/example/quiz/data/remote/StompManager.java +++ b/app/src/main/java/com/example/quiz/data/remote/StompManager.java @@ -1,9 +1,11 @@ package com.example.quiz.data.remote; +import android.content.Context; import android.util.Log; import com.example.quiz.data.model.Course; import com.example.quiz.data.model.dtos.NotifPayload; +import com.example.quiz.utils.SharedPrefsHelper; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -17,6 +19,7 @@ import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; +import dagger.hilt.android.qualifiers.ApplicationContext; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; @@ -34,6 +37,10 @@ public class StompManager { private StompClient stompClient; private boolean isConnected = false; + private String url = "wss://api-alr.pmu.ml/ws"; + + SharedPrefsHelper prefsHelper; + // Map topic -> liste de listeners private final Map>> topicListeners = new HashMap<>(); @@ -42,10 +49,40 @@ public class StompManager { // Map pour stocker les subscriptions par topic private final Map topicSubscriptions = new HashMap<>(); + private String genererUrlWebSocket(String httpUrl) { + if (httpUrl == null || httpUrl.isEmpty()) { + return "wss://api-alr.pmu.ml/ws"; // Sécurité au cas où + } + + String wsUrl = httpUrl; + + // 1. On remplace le protocole au début + if (wsUrl.startsWith("https://")) { + wsUrl = wsUrl.replace("https://", "wss://"); + } else if (wsUrl.startsWith("http://")) { + wsUrl = wsUrl.replace("http://", "ws://"); + } + + // 2. On remplace la route finale "/api/" ou "/api" par "/ws" + if (wsUrl.endsWith("/api/")) { + // Enlève "/api/" (5 caractères) à la fin et ajoute "/ws" + wsUrl = wsUrl.substring(0, wsUrl.length() - 5) + "/ws"; + } else if (wsUrl.endsWith("/api")) { + // Enlève "/api" (4 caractères) à la fin et ajoute "/ws" + wsUrl = wsUrl.substring(0, wsUrl.length() - 4) + "/ws"; + } + + return wsUrl; + } @Inject public StompManager(TokenManager tokenManager, - NotificationHelper notificationHelper) { + NotificationHelper notificationHelper, Context context) { + prefsHelper = SharedPrefsHelper.getInstance(context); + String apiUrl = prefsHelper.get("MAIN_API_URL"); + if(apiUrl != null){ + url = genererUrlWebSocket(apiUrl); + } this.tokenManager = tokenManager; this.notificationHelper = notificationHelper; } @@ -61,7 +98,7 @@ public class StompManager { } // URL de connexion WebSocket - String url = "wss://alr.pmu.ml/ws"; + try { // Créer le client STOMP @@ -162,12 +199,12 @@ public class StompManager { NotifPayload notifCourse = new Gson().fromJson(payload, type); Course updatedCourse = notifCourse.getPayload(); switch (notifCourse.getType()){ - case COURSE_CREATED: - notif = "Nouvelle course "+updatedCourse.getNom()+" créée"; - break; - case COURSE_UPDATED: - notif = "Course "+updatedCourse.getNom()+" modifiée"; - break; + case COURSE_UPDATED:{ + if(updatedCourse.getStatut() == Course.Statut.OUVERT){ + notif = "Course "+updatedCourse.getNom()+" a été créée avec succès"; + break; + } + } case COURSE_CANCELLED: notif = "Course "+updatedCourse.getNom()+" annulée"; break; @@ -181,7 +218,7 @@ public class StompManager { notif = "Non partants déclarés pour la course "+updatedCourse.getNom(); break; } - // Notification + if(notif.isEmpty()) return; notificationHelper.showNotification(topic, notif); }, throwable -> { diff --git a/app/src/main/java/com/example/quiz/data/repository/LoginRepository.java b/app/src/main/java/com/example/quiz/data/repository/LoginRepository.java index 2750031..15af96c 100644 --- a/app/src/main/java/com/example/quiz/data/repository/LoginRepository.java +++ b/app/src/main/java/com/example/quiz/data/repository/LoginRepository.java @@ -45,6 +45,10 @@ public class LoginRepository { }else{ try { String error = response.errorBody().string(); + if(!error.startsWith("{")){ + liveLogin.postValue(Result.error(error)); + return; + } Gson gson = new Gson(); ResponseError errorResponse = gson.fromJson(error, ResponseError.class); liveLogin.postValue(Result.error(errorResponse.getMessage())); diff --git a/app/src/main/java/com/example/quiz/data/repository/PariRepository.java b/app/src/main/java/com/example/quiz/data/repository/PariRepository.java index ddc31cf..bc40b4f 100644 --- a/app/src/main/java/com/example/quiz/data/repository/PariRepository.java +++ b/app/src/main/java/com/example/quiz/data/repository/PariRepository.java @@ -148,10 +148,10 @@ public class PariRepository { return pariResponse; } - public LiveData> annulerPari(String numeroTicket){ + public LiveData> annulerPari(String numeroTicket, String agentId){ MutableLiveData> pariResponse = new MutableLiveData<>(); pariResponse.setValue(Result.loading()); - apiService.annulerPari(numeroTicket).enqueue(new Callback(){ + apiService.annulerPari(numeroTicket, agentId).enqueue(new Callback(){ @Override public void onResponse(Call call, Response response) { if(response.isSuccessful()){ diff --git a/app/src/main/java/com/example/quiz/data/repository/RapportCourseRepository.java b/app/src/main/java/com/example/quiz/data/repository/RapportCourseRepository.java new file mode 100644 index 0000000..4e75641 --- /dev/null +++ b/app/src/main/java/com/example/quiz/data/repository/RapportCourseRepository.java @@ -0,0 +1,57 @@ +package com.example.quiz.data.repository; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.example.quiz.data.model.RaceReport; +import com.example.quiz.data.model.ResponseError; +import com.example.quiz.data.remote.ReportApiService; +import com.example.quiz.utils.Result; +import com.google.gson.Gson; + +import javax.inject.Inject; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class RapportCourseRepository { + private final ReportApiService reportApiService; + + @Inject + public RapportCourseRepository(ReportApiService reportApiService) { + this.reportApiService = reportApiService; + } + + public LiveData> getRaceReport(String courseId) { + MutableLiveData> raceReport = new MutableLiveData<>(); + raceReport.setValue(Result.loading()); + reportApiService.getRaceReport(courseId).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(response.isSuccessful() && response.body() != null){ + raceReport.postValue(Result.success(response.body())); + }else{ + if(response.code() == 404){ + raceReport.postValue(Result.error("Aucun rapport disponible pour cette course")); + }else{ + try { + String error = response.errorBody().string(); + Gson gson = new Gson(); + ResponseError errorResponse = gson.fromJson(error, ResponseError.class); + raceReport.postValue(Result.error(errorResponse.getMessage())); + } catch (Exception e) { + raceReport.postValue(Result.error("Erreur serveur")); + } + } + } + } + + @Override + public void onFailure(Call call, Throwable throwable) { + raceReport.postValue(Result.error(throwable.getMessage())); + } + }); + return raceReport; + } +} diff --git a/app/src/main/java/com/example/quiz/utils/AuthNavigator.java b/app/src/main/java/com/example/quiz/utils/AuthNavigator.java index 3a984b2..4f42025 100644 --- a/app/src/main/java/com/example/quiz/utils/AuthNavigator.java +++ b/app/src/main/java/com/example/quiz/utils/AuthNavigator.java @@ -103,8 +103,9 @@ public class AuthNavigator { pin.setError("Le pin doit contenir minimum quatre chiffres!"); return; } - if(prefsHelper.get("terminalId") == null){ + if(prefsHelper== null || prefsHelper.get("terminalId") == null){ MessageDialog.showError(context, "Terminal non trouvé"); + return; } LoginPayload loginPayload = new LoginPayload( code.getText().toString(), diff --git a/app/src/main/java/com/example/quiz/utils/BitMapUtils.java b/app/src/main/java/com/example/quiz/utils/BitMapUtils.java index 2dca5d8..8051ac5 100644 --- a/app/src/main/java/com/example/quiz/utils/BitMapUtils.java +++ b/app/src/main/java/com/example/quiz/utils/BitMapUtils.java @@ -12,9 +12,12 @@ import com.google.zxing.common.BitMatrix; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.stream.Collectors; public class BitMapUtils { @@ -154,11 +157,7 @@ public class BitMapUtils { if(numbers.length <= requiredHorse){ return Arrays.stream(numbers).map(String::valueOf).collect(Collectors.joining("-")).toString(); } - List firstPart = Arrays.stream(numbers).limit(requiredHorse).map(String::valueOf).collect(Collectors.toList()); - List secondPart = Arrays.stream(numbers).skip(requiredHorse).map(String::valueOf).collect(Collectors.toList()); - formatted.addAll(firstPart); - formatted.add("R"); - formatted.addAll(secondPart); + formatted = Arrays.stream(numbers).map(String::valueOf).collect(Collectors.toList()); }else{ formatted = Arrays.stream(numbers).map(String::valueOf).collect(Collectors.toList()); } @@ -182,4 +181,31 @@ public class BitMapUtils { return finalOutput.toString(); } + public static String formatMontant(Object nombre) { + if (nombre == null) return "0"; + + try { + double valeur; + if (nombre instanceof String) { + valeur = Double.parseDouble((String) nombre); + } else { + valeur = ((Number) nombre).doubleValue(); + } + + // On force les espaces comme séparateurs de milliers pour la lisibilité + DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.FRANCE); + symbols.setGroupingSeparator(' '); + + // ###,### : Regroupe par milliers + // .## : Garde max 2 décimales si elles existent (ex: 3178000.50 -> 3 178 000.5) + DecimalFormat df = new DecimalFormat("###,###", symbols); + + return df.format(valeur); + + } catch (Exception e) { + // Sécurité si la String n'est vraiment pas un nombre + return String.valueOf(nombre); + } + } + } diff --git a/app/src/main/java/com/example/quiz/utils/MobiIotPrinterManager.java b/app/src/main/java/com/example/quiz/utils/MobiIotPrinterManager.java index be8be9c..a099f55 100644 --- a/app/src/main/java/com/example/quiz/utils/MobiIotPrinterManager.java +++ b/app/src/main/java/com/example/quiz/utils/MobiIotPrinterManager.java @@ -14,11 +14,17 @@ import android.util.Log; import com.sagereal.printer.PrinterInterface; import java.io.ByteArrayOutputStream; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class MobiIotPrinterManager { private PrinterInterface mPrinter; private static MobiIotPrinterManager instance; private boolean isBinding = false; + + private final ExecutorService printExecutor = Executors.newSingleThreadExecutor(); String TAG = "MOBITAG"; private static final int MAX_CHAR_2_INCH = 32; @@ -51,6 +57,8 @@ public class MobiIotPrinterManager { } }; + + private void testPrinterStatus() { new Thread(() -> { try { @@ -122,39 +130,40 @@ public class MobiIotPrinterManager { }).start(); } - public void printPari(byte[] logo, byte[] barcode, String numeroTicket, String pariText, MobiIotPrinterStatus listener) { + public void printPari(byte[] logo, byte[] barcode, String numeroTicket, StringBuilder pariText, MobiIotPrinterStatus listener) { if (mPrinter == null) { Log.e("PrinterManager", "❌ L'imprimante n'est pas connectée"); listener.printStatusCode(0); return; } - new Thread(()->{ + printExecutor.execute(()->{ try { - int status = mPrinter.getPrinterStatus(); - if (status != 1) { - listener.printStatusCode(2); + mPrinter.printBitmap_in(logo); + if(mPrinter.getPrinterStatus() != 1){ + listener.printStatusCode(0); return; } - mPrinter.printBitmap_in(logo); mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); mPrinter.printBitmap_in(barcode); mPrinter.printText_FullParm("\n" + numeroTicket, 0, 0, 0, 1, false, false); mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); - mPrinter.printText_FullParm(pariText, 0, 0, 0, 0, false, false); + //String[] lines = pariText.toString().split("\n"); + mPrinter.printText_FullParm(pariText.toString(), 0, 0, 0, 0, false, false); mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); mPrinter.printText_FullParm("Powered by PMU-MALI", 0, 0, 0, 1, false, false); mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 0, false, false); mPrinter.printText_FullParm("\n\n\n\n\n\n", 0, 10, 0, 0, false, false); - Thread.sleep(3000); - if (getPrinterStatus() != 1) { + Thread.sleep(3500); + if(mPrinter.getPrinterStatus() != 1){ + mPrinter.printText_FullParm("\u001B@", 0, 0, 0, 0, false, false); listener.printStatusCode(0); - } else { - listener.printStatusCode(1); + return; } + listener.printStatusCode(1); } catch (RemoteException | InterruptedException e) { throw new RuntimeException(e); } - }).start(); + }); } public void printSold(byte[] logo, String title, StringBuilder text, MobiIotPrinterStatus listener) throws RemoteException { @@ -163,7 +172,7 @@ public class MobiIotPrinterManager { listener.printStatusCode(0); return; } - new Thread(()->{ + printExecutor.execute(()->{ try { mPrinter.printBitmap_in(logo); mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); @@ -174,20 +183,51 @@ public class MobiIotPrinterManager { mPrinter.printText_FullParm("Powered by PMU-MALI", 0, 0, 0, 1, false, false); mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 0, false, false); mPrinter.printText_FullParm("\n\n\n\n\n\n", 0, 10, 0, 0, false, false); - Thread.sleep(3000); - if (getPrinterStatus() != 1) { + Thread.sleep(3500); + if(mPrinter.getPrinterStatus() != 1){ listener.printStatusCode(0); - } else { - listener.printStatusCode(1); + return; } + listener.printStatusCode(1); } catch (RemoteException | InterruptedException e) { throw new RuntimeException(e); } - }).start(); + }); } + public void printRapport(byte[] logo, String courseCode, String hippodromeName, String courseName, String arrivee, String nonPartants, StringBuilder text, MobiIotPrinterStatus listener) throws RemoteException { + printExecutor.execute(()->{ + try{ + mPrinter.printBitmap_in(logo); + mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm(courseCode, 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm(hippodromeName, 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm(courseName, 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm("ARRIVEE : "+ arrivee, 0, 0, 0, 0, false, false); + mPrinter.printText_FullParm("NON PARTANTS : "+ nonPartants, 0, 0, 0, 0, false, false); + mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm(text.toString(), 0, 0, 0, 0, false, false); + mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm("DATE : "+ DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(LocalDateTime.now()), 0, 0, 0, 0, false, false); + mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm("Powered by PMU-MALI", 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm("-".repeat(MAX_CHAR_2_INCH), 0, 0, 0, 1, false, false); + mPrinter.printText_FullParm("\n\n\n\n\n\n", 0, 10, 0, 0, false, false); + Thread.sleep(3500); + if(mPrinter.getPrinterStatus() != 1){ + listener.printStatusCode(0); + return; + } + listener.printStatusCode(1); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + public int getPrinterStatus() throws RemoteException { return mPrinter.getPrinterStatus(); } diff --git a/app/src/main/java/com/example/quiz/utils/SharedPrefsHelper.java b/app/src/main/java/com/example/quiz/utils/SharedPrefsHelper.java index 7fddf33..fe24530 100644 --- a/app/src/main/java/com/example/quiz/utils/SharedPrefsHelper.java +++ b/app/src/main/java/com/example/quiz/utils/SharedPrefsHelper.java @@ -28,6 +28,14 @@ public class SharedPrefsHelper { return prefs.getString(key, null); } + public String getString(String key, String defaultValue) { + return prefs.getString(key, defaultValue); + } + + public SharedPreferences.Editor edit(){ + return prefs.edit(); + } + public void clear() { prefs.edit().clear().apply(); } diff --git a/app/src/main/java/com/example/quiz/utils/SunmiPrinterManager.java b/app/src/main/java/com/example/quiz/utils/SunmiPrinterManager.java index e9a6b30..67dbba6 100644 --- a/app/src/main/java/com/example/quiz/utils/SunmiPrinterManager.java +++ b/app/src/main/java/com/example/quiz/utils/SunmiPrinterManager.java @@ -10,6 +10,8 @@ import com.sunmi.peripheral.printer.InnerPrinterManager; import com.sunmi.peripheral.printer.InnerResultCallback; import com.sunmi.peripheral.printer.SunmiPrinterService; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.function.Consumer; @@ -288,6 +290,165 @@ public class SunmiPrinterManager { } } + public void printRapport(Bitmap logo, String courseCode, String hippodromeName, String courseName, String arrivee, String nonPartants, StringBuilder text, PrintStatusListener listener){ + try{ + sunmiPrinter.enterPrinterBuffer(true); + printSimpleImage(logo); + printTextSimple(separationText()); + setAlignment(1, new PrinterListener() { + @Override + public void onSuccess(boolean isSuccess) { + + } + + @Override + public void onResult(int code) { + + } + + @Override + public void onError(String errorMessage) { + + } + }); + printTextSimple(courseCode); + setAlignment(1, new PrinterListener() { + @Override + public void onSuccess(boolean isSuccess) { + + } + + @Override + public void onResult(int code) { + + } + + @Override + public void onError(String errorMessage) { + + } + }); + printTextSimple(hippodromeName); + printTextSimple(courseName); + printTextSimple(separationText()); + setAlignment(0, new PrinterListener() { + @Override + public void onSuccess(boolean isSuccess) { + + } + + @Override + public void onResult(int code) { + + } + + @Override + public void onError(String errorMessage) { + + } + }); + printTextSimple("ARRIVEE : "+ arrivee); + setAlignment(0, new PrinterListener() { + @Override + public void onSuccess(boolean isSuccess) { + + } + + @Override + public void onResult(int code) { + + } + + @Override + public void onError(String errorMessage) { + + } + }); + printTextSimple("NON PARTANTS : "+ nonPartants); + printTextSimple(separationText()); + setAlignment(0, new PrinterListener() { + @Override + public void onSuccess(boolean isSuccess) { + + } + + @Override + public void onResult(int code) { + + } + + @Override + public void onError(String errorMessage) { + + } + }); + printTextSimple(text.toString()); + printTextSimple(separationText()); + setAlignment(1, new PrinterListener() { + @Override + public void onSuccess(boolean isSuccess) { + + } + + @Override + public void onResult(int code) { + + } + + @Override + public void onError(String errorMessage) { + + } + }); + printTextSimple("DATE : "+ DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(LocalDateTime.now())); + printTextSimple(separationText()); + setAlignment(1, new PrinterListener() { + @Override + public void onSuccess(boolean isSuccess) { + + } + + @Override + public void onResult(int code) { + + } + + @Override + public void onError(String errorMessage) { + + } + }); + printTextSimple("Powered by PMU-MALI"); + printTextSimple(separationText()); + printTextSimple(" "); + printTextSimple(" "); + printTextSimple(" "); + sunmiPrinter.exitPrinterBufferWithCallback(true, new InnerResultCallback() { + @Override + public void onRunResult(boolean isSuccess) throws RemoteException { + + } + + @Override + public void onReturnString(String result) throws RemoteException { + + } + + @Override + public void onRaiseException(int code, String msg) throws RemoteException { + + } + + @Override + public void onPrintResult(int code, String msg) throws RemoteException { + listener.onStatusChanged(code == 0); + } + }); + }catch (Exception e){ + throw new RuntimeException(e); + } + } + private boolean readyForPrinting(){ return printerStatus() == 1; } diff --git a/app/src/main/java/com/example/quiz/viewModel/PariViewModel.java b/app/src/main/java/com/example/quiz/viewModel/PariViewModel.java index 9eb81ac..843da07 100644 --- a/app/src/main/java/com/example/quiz/viewModel/PariViewModel.java +++ b/app/src/main/java/com/example/quiz/viewModel/PariViewModel.java @@ -50,8 +50,8 @@ public class PariViewModel extends ViewModel { return pariRepository.derniersParis(agentId); } - public LiveData> annulerPari(String numeroTicket){ - pariAnnule = pariRepository.annulerPari(numeroTicket); + public LiveData> annulerPari(String numeroTicket, String agentId){ + pariAnnule = pariRepository.annulerPari(numeroTicket, agentId); return pariAnnule; } diff --git a/app/src/main/java/com/example/quiz/viewModel/RapportCourseViewModel.java b/app/src/main/java/com/example/quiz/viewModel/RapportCourseViewModel.java new file mode 100644 index 0000000..e70921b --- /dev/null +++ b/app/src/main/java/com/example/quiz/viewModel/RapportCourseViewModel.java @@ -0,0 +1,28 @@ +package com.example.quiz.viewModel; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import com.example.quiz.data.model.RaceReport; +import com.example.quiz.data.repository.RapportCourseRepository; +import com.example.quiz.utils.Result; + +import javax.inject.Inject; + +import dagger.hilt.android.lifecycle.HiltViewModel; + +@HiltViewModel +public class RapportCourseViewModel extends ViewModel { + private final RapportCourseRepository rapportCourseRepository; + private LiveData> raceReport = new MutableLiveData>(); + @Inject + public RapportCourseViewModel(RapportCourseRepository rapportCourseRepository) { + this.rapportCourseRepository = rapportCourseRepository; + } + + public LiveData> getRaceReport(String courseId) { + raceReport = rapportCourseRepository.getRaceReport(courseId); + return raceReport; + } +} diff --git a/app/src/main/res/layout/fragment_api_url_configuration.xml b/app/src/main/res/layout/fragment_api_url_configuration.xml new file mode 100644 index 0000000..2f56c1a --- /dev/null +++ b/app/src/main/res/layout/fragment_api_url_configuration.xml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +