Để phục vụ cho công việc kinh doanh, mình đang sử dụng khá nhiều các ứng dụng mã nguồn mở để tiết kiệm chi phí vận hành:
-
Odoo: quản lý tồn kho, xuất nhập khẩu, kế toán,…
-
Paperless-ngx: quản lý hồ sơ, biên lai, hóa đơn điện tử
-
WordPress / Woocommerce: tạo blog / trang bán hàng e-commerce
-
Proxmox: quản lý máy ảo, container để cài đặt các ứng dụng web
Từ ngày dọn nhà qua Nhật, có thêm 1 ứng dụng đã nhanh chóng trở thành một phần không thể thiếu cho công ty mới của mình ở Nhật. Đó là Invoice Ninja - ứng dụng tạo và quản lý hóa đơn cho khách hàng. Mình đang sử dụng Invoice Ninja để nhận thanh toán từ khách hàng ở nhiều quốc gia khác nhau, thông qua cổng thanh toán Stripe.
Bài viết này sẽ hướng dẫn bạn cách cài đặt Invoice Ninja để sử dụng cho mục đích kinh doanh của mình
I. Invoice Ninja là gì?
Invoice Ninja là một phần mềm mã nguồn mở giúp bạn quản lý hóa đơn, báo giá, và các khoản thanh toán cho công việc kinh doanh. Nó được thiết kế phù hợp cho các doanh nghiệp nhỏ, freelancer cần một công cụ đơn giản nhưng mạnh mẽ để quản lý tài chính.
Các tính năng nổi bật của Invoice Ninja:
-
Tạo hóa đơn và báo giá chuyên nghiệp.
-
Tích hợp với các cổng thanh toán như Stripe, PayPal, …
-
Hỗ trợ theo dõi chi phí và quản lý dự án.
-
Có thể tự cài đặt lên máy chủ cá nhân để sử dụng miễn phí,
II. Cài đặt Invoice Ninja bằng Docker Compose
Bạn có thể cài đặt Invoice Ninja trực tiếp lên server, hoặc sử dụng Docker. Mình sẽ cài đặt thông qua Docker Compose cho nhanh gọn.
Yêu cầu máy chủ đã được cài đặt sẵn Docker và Docker Compose.
1. Clone Invoice Ninja về server
SSH vào máy chủ và clone repo của Invoice Ninja về máy chủ
git clone https://github.com/invoiceninja/dockerfiles.git -b master invoice-ninjacd invoice-ninjaFile docker-compose.yml sẽ có nội dung tương tự như sau
version: '3.7'
services: server: image: nginx restart: always env_file: env volumes: # Vhost configuration #- ./config/caddy/Caddyfile:/etc/caddy/Caddyfiledocker-com - ./config/nginx/in-vhost.conf:/etc/nginx/conf.d/in-vhost.conf:ro - ./docker/app/public:/var/www/app/public:ro depends_on: - app # Run webserver nginx on port 80 # Feel free to modify depending what port is already occupied ports: - "80:80" #- "443:443" networks: - invoiceninja extra_hosts: - "in5.localhost:192.168.0.124 " #host and ip
app: image: invoiceninja/invoiceninja:5 env_file: env restart: always volumes: - ./config/hosts:/etc/hosts:ro - ./docker/app/public:/var/www/app/public:rw,delegated - ./docker/app/storage:/var/www/app/storage:rw,delegated - ./config/php/php.ini:/usr/local/etc/php/php.ini - ./config/php/php-cli.ini:/usr/local/etc/php/php-cli.ini
depends_on: - db networks: - invoiceninja extra_hosts: - "in5.localhost:192.168.0.124 " #host and ip
db: image: mysql:8# When running on ARM64 use MariaDB instead of MySQL# image: mariadb:10.4# For auto DB backups comment out image and use the build block below# build:# context: ./config/mysql restart: always env_file: env volumes: - ./docker/mysql/data:/var/lib/mysql:rw,delegated
# remove comments for next 4 lines if you want auto sql backups #- ./docker/mysql/bak:/backups:rw #- ./config/mysql/backup-script:/etc/cron.daily/daily:ro #- ./config/mysql/backup-script:/etc/cron.weekly/weekly:ro #- ./config/mysql/backup-script:/etc/cron.monthly/monthly:ro networks: - invoiceninja extra_hosts: - "in5.localhost:192.168.0.124 " #host and ip
# THIS IS ONLY A VALID CONFIGURATION FOR IN 4. DO NOT USE FOR IN 5. # cron: # image: invoiceninja/invoiceninja:alpine-4 # volumes: # - ./docker/app/public:/var/www/app/public:rw,delegated # - ./docker/app/storage:/var/www/app/storage:rw,delegated # - ./docker/app/public/logo:/var/www/app/public/logo:rw,delegated # entrypoint: | # /bin/sh -c 'sh -s <<EOF # trap "break;exit" SIGHUP SIGINT SIGTERM # sleep 300s # while /bin/true; do # ./artisan ninja:send-invoices # ./artisan ninja:send-reminders # sleep 1d # done # EOF' # networks: # - invoiceninja #
networks: invoiceninja:3. Thay thế nginx bằng Caddy
File docker-compose.yml đã được tích hợp Nginx làm Reverse Proxy. Bạn có thể xóa phần khai báo nginx nếu trên hệ thống đã có sẵn Reverse Proxy.
MÌnh không thích dùng nginx nên sẽ thay bằng caddy để làm Reverse Proxy. Đổi lại nội dung file docker-compose.yml như bên dưới
services: server: image: caddy:alpine container_name: caddy restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" volumes: - ./Caddyfile:/etc/caddy/Caddyfile - ./caddy_data:/data - ./caddy_config:/config - ./docker/app/public:/var/www/app/public:ro networks: - invoiceninja
app: image: invoiceninja/invoiceninja:5 container_name: invoiceninja env_file: env restart: always volumes: - ./config/hosts:/etc/hosts:ro - ./docker/app/public:/var/www/app/public:rw,delegated - ./docker/app/storage:/var/www/app/storage:rw,delegated - ./config/php/php.ini:/usr/local/etc/php/php.ini - ./config/php/php-cli.ini:/usr/local/etc/php/php-cli.ini depends_on: - db networks: - invoiceninja
db: image: mariadb:10.4 restart: always env_file: env volumes: - ./docker/mysql/data:/var/lib/mysql:rw,delegated networks: - invoiceninja extra_hosts: - "in5.localhost:192.168.0.124 " #host and ip
networks: invoiceninja:Tạo thêm file Caddyfile với nội dung sau
invoice.thuanbui.me { root * /var/www/app/public php_fastcgi invoiceninja:9000 encode zstd gzip file_server browse}Bạn cần thay thế invoice.thuanbui.me bằng tên miền bạn sử dụng để truy cập Invoice Ninja.
2. Tạo APP_KEY
Trước khi kích hoạt dịch vụ, cần phải tạo APP_KEY bằng lệnh sau
docker run --rm -it invoiceninja/invoiceninja php artisan key:generate --showChờ vài phút để hệ thống xử lý, bạn sẽ nhận được kết quả trả về tương tự như bên dưới
base64:5fOFQtFaQcwFxQ2nAEwBdMUWzB5DcOGS7y+uvkL5W2c=3. Cập nhật thông số env
Chỉnh sửa lại file env bằng lệnh
nano env-
APP_URL: nhập vào tên miền bạn sử dụng để truy cập Invoice Ninja -
APP_KEY: nhập vào thông số đã APP_KEY vừa tạo ở trên
# IN application varsAPP_URL=https://invoice.thuanbui.meAPP_KEY=base64:5fOFQtFaQcwFxQ2nAEwBdMUWzB5DcOGS7y+uvkL5W2c=APP_DEBUG=trueREQUIRE_HTTPS=falsePHANTOMJS_PDF_GENERATION=falsePDF_GENERATOR=snappdfTRUSTED_PROXIES='*'Cập nhật thêm thông số tài khoản admin và mật khẩu
# Create initial user# Default to these values if empty# IN_USER_EMAIL=admin@example.com# IN_PASSWORD=changeme!IN_USER_EMAIL=thuan@thuanbui.meIN_PASSWORD=123456Ngoài ra, để Invoice Ninja có thể gửi email đến khách hàng, cần phải cấu hình thêm mục #Mail options, cần khai báo các thông số cần thiết tương tự như sau
# Mail optionsMAIL_MAILER=smtpMAIL_HOST=smtp.sendgrid.netMAIL_PORT=587MAIL_USERNAME=apikeyMAIL_PASSWORD=SG.wPFD3423dffdsfdsfdsfdsfZxRjSi0T4T-Rn7UsSd2F_-5ySJUV_4MAIL_ENCRYPTION=tlsMAIL_FROM_ADDRESS=noreply@thuanbui.meMAIL_FROM_NAME=ThuanBuiSau khi hoàn thành, lưu lại (Ctrl + O) và thoát ra (Ctrl + X)
4. Chỉnh sửa permission
Để đảm bảo quyền thư mục được thiết lập chính xác khi container khởi động, cần sử dụng lệnh sau thiết lập đúng quyền truy cập cho thư mục Docker.
chmod 755 docker/app/publicsudo chown -R 1500:1500 docker/app3. Kích hoạt dịch vụ
Khởi động Invoice Ninja bằng lệnh
docker compose up -dTruy cập vào Invoice Ninja thông qua tên miền bạn đã cấu hình. Chúng ta sẽ bắt đầu phần cấu hình thông số ban đầu cho Invoice Ninja
III. Cấu hình Invoice Ninja
Bạn cần đăng nhập vào invoice Ninja bằng thông tin email và mật khẩu đã thiết lập trong file env

1. Thông tin công ty
Ở lần đăng nhập đầu tiên, chúng ta cần phải thiết lập tên công ty (Company Name), ngôn ngữ (Language) và tiền tệ (Currency)

Giao diện trang Dashboard của Invoice Ninja sẽ hiện ra như bên dưới

Truy cập thêm vào phần Setting / Company Details để khai báo thêm các thông tin liên quan: Website, Email, Địa chỉ,… Các thông tin này sẽ hiển thị trên các hóa đơn gửi cho khách hàng.

2. Kết nối với Stripe & PayPal
Invoice Ninja hỗ trợ kết nối với cổng thanh toán như Stripe và PayPal giúp khách hàng có thẻ thanh toán trực tiếp từ các hóa đơn được tạo từ hệ thống.
Truy cập vào mục Settings > Payment Settings, chọn Add Gateway, chọn Stripe hoặc Paypal, sau đó nhập các thông tin cần thiết (API Keys) lấy từ tài khoản Stripe / Paypal của bạn

IV. Tạo hóa đơn và nhận thanh toán
1. Tạo hóa đơn mới
-
Truy cập vào Invoices và chọn Create Invoice.
-
Thêm thông tin khách hàng, dịch vụ/sản phẩm, thuế (nếu có).
-
Tùy chỉnh hóa đơn theo ý muốn (logo, màu sắc, điều khoản).

Sau khi hoàn tất, nhấn nút Save để lưu lại invoice.
2. Gửi invoice cho khách hàng
Bạn có thể gửi invoice cho khách hàng bằng 2 cách:
-
Bấm vào nút mũi tên bên cạch nút Save và chọn Email Invoice để gửi invoice qua email
-
Right click vào dòng View in Portal, chọn Copy Link. Sau đó gửi link này cho khách hàng qua Zalo / Facebook / SMS/…

3. Nhận thanh toán
Khách hàng sau khi nhận invoice email / portal link có thể thanh toán bằng Stripe / Paypal (nếu bạn đã cấu hình). Sau khi thanh toán thành công, hóa đơn sẽ được tự động cập nhật trạng thái từ Sent thành Paid.

Invoice Ninja đã giúp mình tiết kiệm rất nhiều thời gian và công sức trong việc quản lý hóa đơn cho công ty. Nếu bạn đang tìm kiếm một công cụ quản lý hóa đơn và để nhận thanh toán từ khách hàng hãy thử cài đặt và sử dụng Invoice Ninja.
Chúc bạn thực hiện thành công!
Nếu bạn cần hỗ trợ thiết lập Invoice Ninja, tham khảo dịch vụ cài đặt Self-Hosting app của mình bên dưới nhé