Projects

Some projects I've worked on

Note

If you want to collaborate or contribute to any project, feel free to clone/fork or contact me for a new project!

EMR-RV

EMR-RV is a web system for managing clinical events and patient records.

Its aim is to help nurses and doctors to manage the clinical and non-clinical data.

For example, for the nursing team, EMR-RV allows to manage vital signs, medications, and food intake and hours.

For the doctors, EMR-RV allows to manage the clinical data of the patients.

The system is built with Django. Previously hosted, but now it's only available in the local network.

from django.shortcuts import render, redirect
from django.views.generic import ListView, CreateView, View, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Medication, Patient, MedicationControl, ArterialPressure, FoodIngestion, TherapyMedicalRecord, FoodDaily, NurseCarerRecord, MedicalRecord, TherapyMedicalValoration
from .forms import MedicationForm, MedicationControlForm, ArterialPressureForm, TherapyMedicalRecordForm, FoodDailyForm, NurseCarerRecordForm, MedicalRecordForm, TherapyMedicalValorationForm, FoodIngestionForm
from datetime import date, timedelta, datetime
from django.contrib.auth.decorators import login_required
from django.contrib import messages

@login_required(login_url='accounts/login/')
def index(request):

    if request.method == 'POST':
        patient_id = request.POST.get('patient_id')
        if patient_id:
            request.session['current_patient_id'] = patient_id


    patients = Patient.objects.all()
    current_patient_id = request.session.get('current_patient_id')
    
    context = {
        'patients': patients,
        'current_patient_id': current_patient_id
    }
    return render(request, 'emr/index.html', context)

EWASyst

EWASystem is a web system for managing quotes, orders, and invoices for a jewelry store in Colombia.

It aim is to provide an easy way to track new clients, their orders, and invoices, and export them in PDF quickly.

Core functionalities include dashboard, growth tracking, and export system.

It is a fully custom made system, with a custom made UI and logo.

The system is hosted in a Linux server using Docker.

from django.shortcuts import render
from .models import Quote
from .forms import QuoteForm
from django.urls import reverse_lazy, reverse
from django.core.mail import BadHeaderError, send_mail, EmailMessage
from django.http import HttpResponse, HttpResponseRedirect
from django.views.generic import ListView, View
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic import DetailView
from invoices.models import Invoice
from invoices.forms import InvoiceForm
from django.shortcuts import redirect
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.contrib import messages
#Generar PDF
import io
from django.http import FileResponse
from reportlab.pdfgen import canvas
import os
from django.conf import settings
from reportlab.lib.utils import simpleSplit
# Create your views here.

class QuoteView(LoginRequiredMixin, ListView):
    model = Quote
    template_name = 'quotes/quotes_list.html'
    context_object_name = 'quotes'
    

class QuoteCreateView(LoginRequiredMixin, CreateView):
    model = Quote
    form_class = QuoteForm
    template_name = 'quotes/quotes_create.html'
    success_url = reverse_lazy('quotes:quotes_list')

class QuoteDetailView(LoginRequiredMixin, DetailView):
    model = Quote
    template_name = 'quotes/quotes_detail.html'
    context_object_name = 'quote'

class QuoteUpdateView(LoginRequiredMixin, UpdateView):
    model = Quote
    form_class = QuoteForm
    template_name = 'quotes/quotes_create.html'

    success_url = reverse_lazy('quotes:quotes_list')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['quote'] = Quote.objects.get(id=self.kwargs['pk'])
        return context

class QuoteDeleteView(LoginRequiredMixin, DeleteView):
    model = Quote
    template_name = 'quotes/quotes_confirm_delete.html'
    success_url = reverse_lazy('quotes:quotes_list')


def create_invoice(request, quote_id):
    quote = Quote.objects.get(id=quote_id)
    
    request.session['invoice_initial_data'] = {
        'client': quote.client.id,  # Store ID instead of object
        'invoice_number': quote.quote_number,
        'invoice_total': str(quote.quote_total),  # Convert Decimal to string
        'observation': quote.quote_description,
        'invoice_quantity': quote.quote_quantity,
        'additional_notes': quote.quote_additional_notes,
        'invoice_type': quote.quote_product_type,
    }

    return redirect('invoices:invoices_create')


class QuoteConfirmEmailView(LoginRequiredMixin, View):
    template_name = 'quotes/quotes_confirm_email.html'
    success_url = reverse_lazy('quotes:quotes_list')
    def get(self, request, *args, **kwargs):
        quote = Quote.objects.get(id=kwargs['quote_id'])
        return render(request, self.template_name, {'quote': quote})
    
    def post(self, request, *args, **kwargs):
        try:
            quote = Quote.objects.get(id=kwargs['quote_id'])
            send_email_quote(request, quote.id)
            messages.add_message(request, messages.SUCCESS, 'Cotización enviada correctamente')
            return redirect(self.success_url)
        except Exception as e:
            messages.add_message(request, messages.ERROR, f"Error: {e}")
            return HttpResponse(f"Error: {e}")

def send_email_quote(request, quote_id):
    quote = Quote.objects.get(id=quote_id)
    subject = f"Cotización {quote.quote_number} EWA JOYERÍA"
    message_body = f"Buenas tardes, segun lo solicitado, la cotización {quote.quote_number} ha sido generada"
    from_email = settings.EMAIL_HOST_USER
    
    if subject and message_body and from_email and quote.client.email:
        try:
            # Create EmailMessage object
            email = EmailMessage(
                subject=subject,
                body=message_body,
                from_email=from_email,
                to=[quote.client.email]
            )
            
            # Generate PDF and attach it
            pdf_response = generate_pdf(request, quote_id)
            pdf_content = b''.join(pdf_response.streaming_content)
            
            email.attach(
                filename=f"cotizacion_{quote.quote_number}.pdf",
                content=pdf_content,
                mimetype='application/pdf'
            )
            
            # Send the email
            email.send()
            quote.email_sent = True
            quote.save()
            print("Email sent successfully")
            return HttpResponseRedirect(reverse('quotes:quotes_list'))
        except BadHeaderError:
            print("Invalid header found.")
            return HttpResponse("Invalid header found.")
        except Exception as e:
            print(f"Error sending email: {e}")
            return HttpResponse(f"Error sending email: {e}")
    else:
        return HttpResponse("Make sure all fields are entered and valid.")
TransmiPay

TransmiPay is a mobile application made with Flutter for public transportation in Colombia. Its aim is to provide a seamless and efficient way to recharge your public transportation card at any time, everywhere, without the need to go to a physical store.

The app has a digital wallet that allows to use trust services to add credits to the account (google pay, apple pay, etc.).

NFC technology is used to read the card and add credits to the card.

The app has a dashboard that allows to see the balance of the card and the history of the transactions.

For now, the app is only available in Colombia.

Fully developed by me.

import 'dart:async';
import 'dart:io' show Platform, sleep;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
import 'package:ndef/ndef.dart' as ndef;
import 'package:transmi_pay/src/record-setting/raw_record_setting.dart';
import 'package:transmi_pay/src/record-setting/text_record_setting.dart';
import 'package:transmi_pay/src/record-setting/uri_record_setting.dart';



void main() => runApp(MaterialApp(home: MyApp()));

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  String _platformVersion =
      '${Platform.operatingSystem} ${Platform.operatingSystemVersion}';
  NFCAvailability _availability = NFCAvailability.not_supported;
  NFCTag? _tag;
  String? _result, _writeResult;
  TabController? _tabController;
  List<ndef.NDEFRecord>? _records;

  @override
  void dispose() {
    _tabController!.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    initPlatformState();
    _tabController = new TabController(length: 2, vsync: this);
    _records = [];
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    NFCAvailability availability;
    try {
      availability = await FlutterNfcKit.nfcAvailability;
    } on PlatformException {
      availability = NFCAvailability.not_supported;
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      // _platformVersion = platformVersion;
      _availability = availability;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
            title: const Text('TransmiPay'),
            bottom: TabBar(
              tabs: <Widget>[
                Tab(text: 'read'),
                Tab(text: 'write'),
              ],
              controller: _tabController,
            )),
        body: new TabBarView(controller: _tabController, children: <Widget>[
          Scrollbar(
              child: SingleChildScrollView(
                  child: Center(
                      child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                Text('Running on: $_platformVersion\nNFC: $_availability'),
                ElevatedButton(
                  onPressed: () async {
                    try {
                      NFCTag tag = await FlutterNfcKit.poll();
                      setState(() {
                        _tag = tag;
                      });
                      await FlutterNfcKit.setIosAlertMessage(
                          "working on it...");
                      if (tag.standard == "ISO 14443-4 (Type B)") {
                ..........