Skip to content

Commit

Permalink
Merge branch 'release/0.1.12.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
akhilgkrishnan committed May 26, 2022
2 parents 13e5b76 + f23568e commit 005fe56
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 20 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@

Miru is an open-source tool, designed to make time tracking, invoice management, and accounting easy for small businesses worldwide. It is a platform for organizations to help them streamline their workflow.

![GitHub contributors](https://img.shields.io/github/contributors/saeloun/miru-web)
[![GitHub stars](https://img.shields.io/github/stars/saeloun/miru-web)](https://github.com/saeloun/miru-web/stargazers)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/saeloun/miru-web)
![GitHub commit activity](https://img.shields.io/github/commit-activity/m/saeloun/miru-web)
[![GitHub license](https://img.shields.io/github/license/saeloun/miru-web)](https://github.com/saeloun/miru-web)
[![Twitter Follow](https://img.shields.io/twitter/follow/GetMiru?style=social)](https://twitter.com/getmiru)

<img src="https://user-images.githubusercontent.com/22231095/170423540-e10ada9e-cf1b-4a05-bbb6-2342955f46b0.png" width="100%" alt="Miru Monthly Timetracking page"/>

<img src="https://user-images.githubusercontent.com/22231095/170424136-42f45a24-caa9-4b0e-b5fa-35bfe6f2e70b.png" width="100%" alt="Miru Invoice page"/>

---

## Installation

1. Clone repo to local
Expand Down
7 changes: 5 additions & 2 deletions app/javascript/src/components/Invoices/Invoice/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import BackButton from "./BackButton";
import InvoiceActions from "./InvoiceActions";
import InvoiceStatus from "./InvoiceStatus";

const Header = ({ invoice, handleSendInvoice }) => (
const Header = ({ invoice, handleSendInvoice, setShowDeleteDialog, setInvoiceToDelete }) => (
<>
<div className="mt-6 mb-3 sm:flex sm:items-center sm:justify-between">
<div className="flex flex-row">
<BackButton href="/invoices" />
<InvoiceStatus invoice={invoice} />
</div>
<InvoiceActions
deleteInvoice={() => { alert("Implement me!"); }}
deleteInvoice= {()=> {
setShowDeleteDialog(true);
setInvoiceToDelete(invoice.id);
}}
editInvoiceLink={`/invoices/${invoice.id}/edit`}
sendInvoice={handleSendInvoice}
/>
Expand Down
12 changes: 11 additions & 1 deletion app/javascript/src/components/Invoices/Invoice/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import invoicesApi from "apis/invoices";
import Header from "./Header";
import InvoiceDetails from "./InvoiceDetails";
import { ApiStatus as InvoiceStatus } from "../../../constants";
import DeleteInvoice from "../popups/DeleteInvoice";
import SendInvoice from "../popups/SendInvoice";

const Invoice = () => {
Expand All @@ -15,6 +16,8 @@ const Invoice = () => {
);
const [invoice, setInvoice] = useState<any>(null);
const [showSendInvoiceModal, setShowInvoiceModal] = useState<boolean>(false);
const [invoiceToDelete, setInvoiceToDelete] = React.useState(null);
const [showDeleteDialog, setShowDeleteDialog] = React.useState<boolean>(false);
const fetchInvoice = async () => {
try {
setStatus(InvoiceStatus.LOADING);
Expand All @@ -39,11 +42,18 @@ const Invoice = () => {
return (
status === InvoiceStatus.SUCCESS && (
<>
<Header invoice={invoice} handleSendInvoice={handleSendInvoice} />
<Header invoice={invoice} handleSendInvoice={handleSendInvoice} setShowDeleteDialog={setShowDeleteDialog}
setInvoiceToDelete={setInvoiceToDelete} />
<div className="bg-miru-gray-100 mt-5 mb-10 p-0 m-0 w-full">
<InvoiceDetails invoice={invoice} />
</div>
{showSendInvoiceModal && <SendInvoice invoice={invoice} setIsSending={setShowInvoiceModal} isSending={showSendInvoiceModal} />}
{showDeleteDialog && (
<DeleteInvoice
invoice={invoiceToDelete}
setShowDeleteDialog={setShowDeleteDialog}
/>
)}
</>
)
);
Expand Down
10 changes: 8 additions & 2 deletions app/javascript/src/components/Invoices/popups/DeleteInvoice.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import invoicesApi from "apis/invoices";

interface IProps {
invoice: any;
setShowDeleteDialog: any;
fetchInvoices: any;
fetchInvoices?: any;
}

const DeleteInvoice = ({ invoice, setShowDeleteDialog, fetchInvoices }: IProps) => {
const navigate = useNavigate();
const destroyInvoice = async invoice => {
try {
await invoicesApi.destroy(invoice);
setShowDeleteDialog(false);
fetchInvoices();
if (fetchInvoices) {
fetchInvoices();
} else {
navigate("/invoices");
}
} catch (error) {
console.error(error);
}
Expand Down
6 changes: 6 additions & 0 deletions app/models/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ def register_on_stripe!
metadata: {
platform_id: id
}
}, {
stripe_account: stripe_connected_account.account_id
})

update!(stripe_id: customer.id)
Expand All @@ -129,6 +131,10 @@ def register_on_stripe!

private

def stripe_connected_account
StripeConnectedAccount.find_by!(company:)
end

def discard_projects
projects.discard_all
end
Expand Down
16 changes: 13 additions & 3 deletions app/services/invoice_payment/pdf_generation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@ def initialize(invoice, company_logo)

def process
formatted_invoice = format_invoice(@invoice.invoice_line_items)

base_currency = @invoice.company.base_currency
controller = ActionController::Base.new
html = controller.render_to_string(
template: "invoices/pdf",
layout: "layouts/pdf",
locals: {
invoice: @invoice,
invoice_amount: format_currency(base_currency, @invoice.amount),
invoice_tax: format_currency(base_currency, @invoice.tax),
invoice_amount_due: format_currency(base_currency, @invoice.amount_due),
invoice_amount_paid: format_currency(base_currency, @invoice.amount_paid),
invoice_discount: format_currency(base_currency, @invoice.discount),
company_logo: @company_logo,
client: @invoice.client,
invoice_line_items: formatted_invoice[:invoice_line_items],
sub_total: formatted_invoice[:sub_total],
total: formatted_invoice[:total]
sub_total: format_currency(base_currency, formatted_invoice[:sub_total]),
total: format_currency(base_currency, formatted_invoice[:total])
}
)

Expand Down Expand Up @@ -56,5 +61,10 @@ def format_invoice(invoice_line_items)
total: sub_total + @invoice.tax - @invoice.discount
}
end

def format_currency(base_currency, amount)
Money.locale_backend = :currency
Money.from_amount(amount, base_currency).format
end
end
end
22 changes: 11 additions & 11 deletions app/views/invoices/pdf.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ html {
}
</style>
<div class="main">
<div class="flex justify-between border-b-2 border-miru-gray-400 p-10 h-40">
<div class="flex justify-between border-b-2 border-miru-gray-400 p-10 h-50">
<div class="flex">
<div class="h-20 w-20 mr-5">
<%=image_tag company_logo%>
Expand All @@ -19,7 +19,7 @@ html {
</p>
</div>
</div>
<div class="mt-2 font-normal text-base text-right text-miru-dark-purple-1000 w-36">
<div class="mt-2 font-normal text-base text-right text-miru-dark-purple-1000 w-40">
<p><%=invoice.company.address%></p>
<p><%=invoice.company.country%></p>
</div>
Expand All @@ -40,11 +40,11 @@ html {
<div class="group">
<p class="font-normal text-xs text-miru-dark-purple-1000 flex">Date of Issue</p>
<p class="font-normal text-base text-miru-dark-purple-1000">
<%=invoice["issue_date"]%>
<%=invoice["issue_date"].strftime('%d-%m-%Y')%>
</p>
<p class="font-normal text-xs text-miru-dark-purple-1000 mt-4">Due Date</p>
<p class="font-normal text-base text-miru-dark-purple-1000">
<%=invoice["issue_date"]%>
<%=invoice["due_date"].strftime('%d-%m-%Y')%>
</p>
</div>
<div class="group">
Expand All @@ -60,7 +60,7 @@ html {
<div>
<p class="font-normal text-xs text-miru-dark-purple-1000 text-right">Amount</p>
<p class="font-normal text-4xl text-miru-dark-purple-1000 mt-1">
<%="#{invoice.company.base_currency} #{invoice["amount"]}"%>
<%=invoice_amount%>
</p>
</div>
</div>
Expand All @@ -80,7 +80,7 @@ html {
<%invoice_line_items.each do |item| %>
<tr>
<td class="border-b-2 border-miru-gray-200 px-1 py-3 font-normal text-base text-miru-dark-purple-1000 text-left "><%=item[:name]%></td>
<td class="border-b-2 border-miru-gray-200 py-3 font-normal text-base text-miru-dark-purple-1000 text-left"><%=item[:date]%></td>
<td class="border-b-2 border-miru-gray-200 py-3 font-normal text-base text-miru-dark-purple-1000 text-left"><%=item[:date].strftime('%d-%m-%Y')%></td>
<td class="border-b-2 border-miru-gray-200 px-1 pl-2 py-3 font-normal text-base text-miru-dark-purple-1000 text-left ">
<%=item[:description]%>
</td>
Expand All @@ -107,28 +107,28 @@ html {
</tr>
<tr class="pb-5 border-b-2 miru-gray-400 ">
<td class="py-2 font-normal text-base text-miru-dark-purple-1000 text-right pr-10">Discount</td>
<td class="font-bold text-base text-miru-dark-purple-1000 text-right "><%=invoice["discount"]%></td>
<td class="font-bold text-base text-miru-dark-purple-1000 text-right "><%=invoice_discount%></td>
</tr>
<tr>
<td class="pt-4 font-normal text-base text-miru-dark-purple-1000 text-right pr-10">Tax</td>
<td class="pt-4 font-bold text-base text-miru-dark-purple-1000 text-right w-22">
<%="#{invoice.company.base_currency} #{invoice["tax"]}"%>
<%=invoice_tax%>
</td>
</tr>
<tr>
<td class="pt-1 font-normal text-base text-miru-dark-purple-1000 text-right pr-10">Total</td>
<td class="font-bold text-base text-miru-dark-purple-1000 text-right">
<%="#{invoice.company.base_currency} #{total}"%>
<%=total%>
</td>
</tr>
<tr>
<td class="pt-1 font-normal text-base text-miru-dark-purple-1000 text-right pr-10">Amount Paid</td>
<td class="font-bold text-base text-miru-dark-purple-1000 text-right "><%="#{invoice.company.base_currency} #{invoice["amount_paid"]}"%></td>
<td class="font-bold text-base text-miru-dark-purple-1000 text-right "><%=invoice_amount_paid%></td>
</tr>
<tr>
<td class="pt-1 font-normal text-base text-miru-dark-purple-1000 text-right pr-10">Amount Due</td>
<td class="font-bold text-base text-miru-dark-purple-1000 text-right">
<%="#{invoice.company.base_currency} #{invoice["amount_due"]}"%>
<%=invoice_amount_due%>
</td>
</tr>
</tbody>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@saeloun/miru-web",
"version": "0.1.12",
"version": "0.1.13",
"dependencies": {
"@babel/plugin-proposal-private-methods": "^7.16.5",
"@babel/preset-react": "^7.16.5",
Expand Down
25 changes: 25 additions & 0 deletions spec/models/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -233,5 +233,30 @@
expect(client.client_overdue_and_outstanding_calculation).to match_array(result)
end
end

describe "#register_on_stripe!" do
let(:company) { create(:company) }
let(:user) { create(:user) }
let(:client) { create(:client, company:) }

context "when associated stripe connected account doesn't exist" do
it "raises ActiveRecord::RecordNotFound" do
expect { client.register_on_stripe! }.to raise_error(ActiveRecord::RecordNotFound)
end
end

context "when associated stripe connected account exists" do
let(:stripe_connected_account) { build(:stripe_connected_account, company:) }

it "creates customer for the connected account" do
allow(Stripe::Account).to receive(:create)
.and_return(OpenStruct.new({ id: stripe_connected_account.account_id }))
allow(Stripe::Customer).to receive(:create)
.and_return(OpenStruct.new({ id: 123 }))
stripe_connected_account.save!
expect(client.register_on_stripe!).to eq(true)
end
end
end
end
end

0 comments on commit 005fe56

Please sign in to comment.