add payment section
This commit is contained in:
@@ -328,7 +328,7 @@ def _get_due_days(
|
|||||||
return dyn.collection.get_item(
|
return dyn.collection.get_item(
|
||||||
KeyPair(
|
KeyPair(
|
||||||
pk=str(org_id),
|
pk=str(org_id),
|
||||||
sk=SortKey('METADATA#PAYMENT_POLICY', path_spec='due_days'),
|
sk=SortKey('METADATA#BILLING', path_spec='due_days'),
|
||||||
),
|
),
|
||||||
raise_on_error=False,
|
raise_on_error=False,
|
||||||
default=default,
|
default=default,
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ def get_org(org_id: str):
|
|||||||
TransactKey(org_id)
|
TransactKey(org_id)
|
||||||
+ SortKey('0')
|
+ SortKey('0')
|
||||||
+ SortKey('METADATA#ADDRESS', rename_key='address')
|
+ SortKey('METADATA#ADDRESS', rename_key='address')
|
||||||
|
+ SortKey('METADATA#BILLING', rename_key='billing')
|
||||||
+ SortKey('METADATA#SUBSCRIPTION', rename_key='subscription')
|
+ SortKey('METADATA#SUBSCRIPTION', rename_key='subscription')
|
||||||
+ KeyPair(
|
+ KeyPair(
|
||||||
pk='SUBSCRIPTION#FROZEN',
|
pk='SUBSCRIPTION#FROZEN',
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
|
from decimal import Decimal
|
||||||
|
from enum import Enum
|
||||||
|
from http import HTTPStatus
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
|
||||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||||
from aws_lambda_powertools.event_handler.exceptions import NotFoundError
|
from aws_lambda_powertools.event_handler.exceptions import NotFoundError
|
||||||
from aws_lambda_powertools.event_handler.openapi.params import Query
|
from aws_lambda_powertools.event_handler.openapi.params import Body, Query
|
||||||
|
from layercake.dateutils import now
|
||||||
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
||||||
|
|
||||||
|
from api_gateway import JSONResponse
|
||||||
from boto3clients import dynamodb_client
|
from boto3clients import dynamodb_client
|
||||||
from config import ORDER_TABLE
|
from config import ORDER_TABLE, USER_TABLE
|
||||||
|
from exceptions import OrgNotFoundError
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
|
dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
|
||||||
@@ -16,6 +22,11 @@ dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
|
|||||||
class BillingNotFoundError(NotFoundError): ...
|
class BillingNotFoundError(NotFoundError): ...
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentMethod(str, Enum):
|
||||||
|
BANK_SLIP = 'BANK_SLIP'
|
||||||
|
MANUAL = 'MANUAL'
|
||||||
|
|
||||||
|
|
||||||
@router.get('/<org_id>/billing')
|
@router.get('/<org_id>/billing')
|
||||||
def billing(
|
def billing(
|
||||||
org_id: str,
|
org_id: str,
|
||||||
@@ -36,3 +47,30 @@ def billing(
|
|||||||
),
|
),
|
||||||
limit=150,
|
limit=150,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.put('/<org_id>/billing')
|
||||||
|
def update(
|
||||||
|
org_id: str,
|
||||||
|
due_days: Annotated[Decimal, Body(embed=True, ge=1, le=90)],
|
||||||
|
payment_method: Annotated[PaymentMethod, Body(embed=True)],
|
||||||
|
):
|
||||||
|
with dyn.transact_writer() as transact:
|
||||||
|
transact.condition(
|
||||||
|
key=KeyPair(org_id, '0'),
|
||||||
|
cond_expr='attribute_exists(sk)',
|
||||||
|
exc_cls=OrgNotFoundError,
|
||||||
|
table_name=USER_TABLE,
|
||||||
|
)
|
||||||
|
transact.put(
|
||||||
|
item={
|
||||||
|
'id': org_id,
|
||||||
|
'sk': 'METADATA#BILLING',
|
||||||
|
'due_days': due_days,
|
||||||
|
'payment_method': payment_method.value,
|
||||||
|
'created_at': now(),
|
||||||
|
},
|
||||||
|
table_name=USER_TABLE,
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(status_code=HTTPStatus.NO_CONTENT)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from enum import Enum
|
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
|
||||||
@@ -20,17 +19,11 @@ router = Router()
|
|||||||
dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
|
dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
|
||||||
|
|
||||||
|
|
||||||
class PaymentMethod(str, Enum):
|
|
||||||
BANK_SLIP = 'BANK_SLIP'
|
|
||||||
MANUAL = 'MANUAL'
|
|
||||||
|
|
||||||
|
|
||||||
@router.post('/<org_id>/subscription')
|
@router.post('/<org_id>/subscription')
|
||||||
def add(
|
def add(
|
||||||
org_id: str,
|
org_id: str,
|
||||||
name: Annotated[str, Body(embed=True)],
|
name: Annotated[str, Body(embed=True)],
|
||||||
billing_day: Annotated[int, Body(embed=True, ge=1, le=31)],
|
billing_day: Annotated[int, Body(embed=True, ge=1, le=31)],
|
||||||
payment_method: Annotated[PaymentMethod, Body(embed=True)],
|
|
||||||
subscription_frozen: Annotated[bool, Body(embed=True)] = False,
|
subscription_frozen: Annotated[bool, Body(embed=True)] = False,
|
||||||
):
|
):
|
||||||
now_ = now()
|
now_ = now()
|
||||||
@@ -55,7 +48,6 @@ def add(
|
|||||||
'id': org_id,
|
'id': org_id,
|
||||||
'sk': 'METADATA#SUBSCRIPTION',
|
'sk': 'METADATA#SUBSCRIPTION',
|
||||||
'billing_day': billing_day,
|
'billing_day': billing_day,
|
||||||
'payment_method': payment_method.value,
|
|
||||||
'created_at': now_,
|
'created_at': now_,
|
||||||
},
|
},
|
||||||
cond_expr='attribute_not_exists(sk)',
|
cond_expr='attribute_not_exists(sk)',
|
||||||
@@ -88,7 +80,6 @@ def add(
|
|||||||
def edit(
|
def edit(
|
||||||
org_id: str,
|
org_id: str,
|
||||||
billing_day: Annotated[int, Body(embed=True, ge=1, le=31)],
|
billing_day: Annotated[int, Body(embed=True, ge=1, le=31)],
|
||||||
payment_method: Annotated[PaymentMethod, Body(embed=True)],
|
|
||||||
subscription_frozen: Annotated[bool, Body(embed=True)] = False,
|
subscription_frozen: Annotated[bool, Body(embed=True)] = False,
|
||||||
):
|
):
|
||||||
now_ = now()
|
now_ = now()
|
||||||
@@ -102,11 +93,9 @@ def edit(
|
|||||||
transact.update(
|
transact.update(
|
||||||
key=KeyPair(org_id, 'METADATA#SUBSCRIPTION'),
|
key=KeyPair(org_id, 'METADATA#SUBSCRIPTION'),
|
||||||
update_expr='SET billing_day = :billing_day, \
|
update_expr='SET billing_day = :billing_day, \
|
||||||
payment_method = :payment_method, \
|
|
||||||
updated_at = :now',
|
updated_at = :now',
|
||||||
expr_attr_values={
|
expr_attr_values={
|
||||||
':billing_day': billing_day,
|
':billing_day': billing_day,
|
||||||
':payment_method': payment_method.value,
|
|
||||||
':now': now_,
|
':now': now_,
|
||||||
},
|
},
|
||||||
cond_expr='attribute_exists(sk)',
|
cond_expr='attribute_exists(sk)',
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export const TZ = 'America/Sao_Paulo'
|
export const TZ = 'America/Sao_Paulo'
|
||||||
export const INTERNAL_EMAIL_DOMAIN = 'users.noreply.saladeaula.digital'
|
export const INTERNAL_EMAIL_DOMAIN = 'users.noreply.saladeaula.digital'
|
||||||
|
export const RYBBIT_SITE_ID = '83748b35413d'
|
||||||
|
|||||||
@@ -12,12 +12,11 @@ import {
|
|||||||
import { loggingMiddleware } from '@repo/auth/middleware/logging'
|
import { loggingMiddleware } from '@repo/auth/middleware/logging'
|
||||||
import { ThemeProvider } from '@repo/ui/components/theme-provider'
|
import { ThemeProvider } from '@repo/ui/components/theme-provider'
|
||||||
import './app.css'
|
import './app.css'
|
||||||
|
import { RYBBIT_SITE_ID } from './conf'
|
||||||
|
|
||||||
export const middleware: Route.MiddlewareFunction[] = [loggingMiddleware]
|
export const middleware: Route.MiddlewareFunction[] = [loggingMiddleware]
|
||||||
|
|
||||||
export function Layout({ children }: { children: React.ReactNode }) {
|
export function Layout({ children }: { children: React.ReactNode }) {
|
||||||
const rybbitSiteId = '83748b35413d'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="pt-br" suppressHydrationWarning>
|
<html lang="pt-br" suppressHydrationWarning>
|
||||||
<head>
|
<head>
|
||||||
@@ -30,7 +29,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
{/* Rybbit Tracking Snippet */}
|
{/* Rybbit Tracking Snippet */}
|
||||||
<script
|
<script
|
||||||
src="https://analytics.eduseg.com.br/api/script.js"
|
src="https://analytics.eduseg.com.br/api/script.js"
|
||||||
data-site-id={rybbitSiteId}
|
data-site-id={RYBBIT_SITE_ID}
|
||||||
async
|
async
|
||||||
defer
|
defer
|
||||||
></script>
|
></script>
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ export default function Route({}: Route.ComponentProps) {
|
|||||||
Editar empresa
|
Editar empresa
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Configurar as informações gerais para esta empresa.
|
Gerencie as informações cadastrais e configurações gerais desta
|
||||||
|
empresa.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ export default function Route({}: Route.ComponentProps) {
|
|||||||
Editar endereço
|
Editar endereço
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Este endereço será usado automaticamente sempre que for necessário
|
Este endereço será usado automaticamente sempre que necessário.
|
||||||
informar um endereço.
|
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import type { Route } from './+types/route'
|
||||||
|
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod'
|
||||||
|
import { useForm } from 'react-hook-form'
|
||||||
|
import { toast } from 'sonner'
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
import { Button } from '@repo/ui/components/ui/button'
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle
|
||||||
|
} from '@repo/ui/components/ui/card'
|
||||||
|
import { FieldSet } from '@repo/ui/components/ui/field'
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage
|
||||||
|
} from '@repo/ui/components/ui/form'
|
||||||
|
import { Input } from '@repo/ui/components/ui/input'
|
||||||
|
import {
|
||||||
|
NativeSelect,
|
||||||
|
NativeSelectOption
|
||||||
|
} from '@repo/ui/components/ui/native-select'
|
||||||
|
import { Spinner } from '@repo/ui/components/ui/spinner'
|
||||||
|
import { HttpMethod, request as req } from '@repo/util/request'
|
||||||
|
import { useFetcher, useOutletContext } from 'react-router'
|
||||||
|
import type { Org } from '../_app.orgs.$id/data'
|
||||||
|
|
||||||
|
const formSchema = z.object({
|
||||||
|
due_days: z
|
||||||
|
.number({ error: 'Deve estar entre 1 e 90' })
|
||||||
|
.min(1, { error: 'Deve ser igual 1 ou maior' })
|
||||||
|
.max(90, { error: 'Deve ser menor ou igual a 90' }),
|
||||||
|
payment_method: z.enum(['BANK_SLIP', 'MANUAL'], {
|
||||||
|
error: 'Selecione uma opção'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
type Schema = z.infer<typeof formSchema>
|
||||||
|
|
||||||
|
export async function action({ params, request, context }: Route.ActionArgs) {
|
||||||
|
const r = await req({
|
||||||
|
url: `orgs/${params.id}/billing`,
|
||||||
|
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||||
|
method: HttpMethod.PUT,
|
||||||
|
body: JSON.stringify(await request.json()),
|
||||||
|
request,
|
||||||
|
context
|
||||||
|
})
|
||||||
|
|
||||||
|
return { ok: r.ok }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Route({}: Route.ComponentProps) {
|
||||||
|
const fetcher = useFetcher()
|
||||||
|
const { org } = useOutletContext() as { org: Org }
|
||||||
|
const form = useForm<Schema>({
|
||||||
|
resolver: zodResolver(formSchema),
|
||||||
|
defaultValues: org?.billing
|
||||||
|
})
|
||||||
|
const { handleSubmit, control, formState } = form
|
||||||
|
const onSubmit = async (data: Schema) => {
|
||||||
|
toast.success('As condições de pagamento foram atualizadas')
|
||||||
|
|
||||||
|
fetcher.submit(JSON.stringify(data), {
|
||||||
|
method: 'PUT',
|
||||||
|
encType: 'application/json'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form {...form}>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="font-semibold text-lg">
|
||||||
|
Condições de pagamento
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Estas condições serão usadas automaticamente sempre que um
|
||||||
|
pagamento for gerado.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-6">
|
||||||
|
<FieldSet>
|
||||||
|
<FormField
|
||||||
|
control={control}
|
||||||
|
name="due_days"
|
||||||
|
render={({ field: { onChange, ...field } }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>
|
||||||
|
Prazo para vencimento{' '}
|
||||||
|
<span className="text-xs text-white/30 font-normal">
|
||||||
|
(em dias)
|
||||||
|
</span>
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
min={1}
|
||||||
|
max={90}
|
||||||
|
onChange={(e) => onChange(Number(e.target.value))}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={control}
|
||||||
|
name="payment_method"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="*:w-full">
|
||||||
|
<FormLabel>Forma de pagamento</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<NativeSelect {...field}>
|
||||||
|
<NativeSelectOption value="">
|
||||||
|
Selecione
|
||||||
|
</NativeSelectOption>
|
||||||
|
<NativeSelectOption value="BANK_SLIP">
|
||||||
|
Boleto bancário
|
||||||
|
</NativeSelectOption>
|
||||||
|
<NativeSelectOption value="MANUAL">
|
||||||
|
Depósito bancário
|
||||||
|
</NativeSelectOption>
|
||||||
|
<NativeSelectOption value="PIX" disabled>
|
||||||
|
Pix
|
||||||
|
</NativeSelectOption>
|
||||||
|
<NativeSelectOption value="CREDIT_CARD" disabled>
|
||||||
|
Cartão de crédito
|
||||||
|
</NativeSelectOption>
|
||||||
|
</NativeSelect>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FieldSet>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className="cursor-pointer"
|
||||||
|
disabled={formState.isSubmitting}
|
||||||
|
>
|
||||||
|
{formState.isSubmitting ? <Spinner /> : null}
|
||||||
|
Atualizar condições
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -26,10 +26,6 @@ import {
|
|||||||
} from '@repo/ui/components/ui/form'
|
} from '@repo/ui/components/ui/form'
|
||||||
import { Input } from '@repo/ui/components/ui/input'
|
import { Input } from '@repo/ui/components/ui/input'
|
||||||
import { Label } from '@repo/ui/components/ui/label'
|
import { Label } from '@repo/ui/components/ui/label'
|
||||||
import {
|
|
||||||
NativeSelect,
|
|
||||||
NativeSelectOption
|
|
||||||
} from '@repo/ui/components/ui/native-select'
|
|
||||||
import { RadioGroup, RadioGroupItem } from '@repo/ui/components/ui/radio-group'
|
import { RadioGroup, RadioGroupItem } from '@repo/ui/components/ui/radio-group'
|
||||||
import { Spinner } from '@repo/ui/components/ui/spinner'
|
import { Spinner } from '@repo/ui/components/ui/spinner'
|
||||||
import { HttpMethod, request as req } from '@repo/util/request'
|
import { HttpMethod, request as req } from '@repo/util/request'
|
||||||
@@ -42,9 +38,6 @@ const formSchema = z.object({
|
|||||||
.number({ error: 'Deve estar entre 1 e 31' })
|
.number({ error: 'Deve estar entre 1 e 31' })
|
||||||
.min(1, { error: 'Deve ser igual 1 ou maior' })
|
.min(1, { error: 'Deve ser igual 1 ou maior' })
|
||||||
.max(31, { error: 'Deve ser menor ou igual a 31' }),
|
.max(31, { error: 'Deve ser menor ou igual a 31' }),
|
||||||
payment_method: z.enum(['BANK_SLIP', 'MANUAL'], {
|
|
||||||
error: 'Selecione uma opção'
|
|
||||||
}),
|
|
||||||
subscription_frozen: z.boolean().optional()
|
subscription_frozen: z.boolean().optional()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -88,7 +81,7 @@ export default function Route({}: Route.ComponentProps) {
|
|||||||
},
|
},
|
||||||
resolver: zodResolver(formSchema)
|
resolver: zodResolver(formSchema)
|
||||||
})
|
})
|
||||||
const { handleSubmit, formState, watch, reset } = form
|
const { handleSubmit, formState, watch, reset, control } = form
|
||||||
const plan = watch('plan')
|
const plan = watch('plan')
|
||||||
|
|
||||||
const onSubmit = async ({ plan, ...data }: Schema) => {
|
const onSubmit = async ({ plan, ...data }: Schema) => {
|
||||||
@@ -129,7 +122,7 @@ export default function Route({}: Route.ComponentProps) {
|
|||||||
|
|
||||||
<CardContent className="space-y-6">
|
<CardContent className="space-y-6">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={control}
|
||||||
name="plan"
|
name="plan"
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
@@ -166,7 +159,7 @@ export default function Route({}: Route.ComponentProps) {
|
|||||||
|
|
||||||
<FieldGroup>
|
<FieldGroup>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={control}
|
||||||
name="billing_day"
|
name="billing_day"
|
||||||
render={({ field: { onChange, ...field } }) => (
|
render={({ field: { onChange, ...field } }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
@@ -186,31 +179,7 @@ export default function Route({}: Route.ComponentProps) {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={control}
|
||||||
name="payment_method"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="*:w-full">
|
|
||||||
<FormLabel>Forma de pagamento</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<NativeSelect {...field}>
|
|
||||||
<NativeSelectOption value="">
|
|
||||||
Selecione
|
|
||||||
</NativeSelectOption>
|
|
||||||
<NativeSelectOption value="BANK_SLIP">
|
|
||||||
Boleto bancário
|
|
||||||
</NativeSelectOption>
|
|
||||||
<NativeSelectOption value="MANUAL">
|
|
||||||
Depósito bancário
|
|
||||||
</NativeSelectOption>
|
|
||||||
</NativeSelect>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="subscription_frozen"
|
name="subscription_frozen"
|
||||||
defaultValue={false}
|
defaultValue={false}
|
||||||
render={({ field: { onChange, value, ...field } }) => (
|
render={({ field: { onChange, value, ...field } }) => (
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import type { Org as Org_ } from '../_app.orgs._index/columns'
|
|||||||
|
|
||||||
export type Subscription = {
|
export type Subscription = {
|
||||||
billing_day: number
|
billing_day: number
|
||||||
payment_method: 'BANK_SLIP' | 'MANUAL'
|
}
|
||||||
|
|
||||||
|
export type Billing = {
|
||||||
|
due_days: number
|
||||||
|
payment_methot: 'BANK_SLIP' | 'MANUAL'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Address = {
|
export type Address = {
|
||||||
@@ -14,4 +18,5 @@ export type Org = Org_ & {
|
|||||||
address?: Address
|
address?: Address
|
||||||
subscription?: Subscription
|
subscription?: Subscription
|
||||||
subscription_frozen?: boolean
|
subscription_frozen?: boolean
|
||||||
|
billing: Billing
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ import type { Org } from './data'
|
|||||||
const links = [
|
const links = [
|
||||||
{ to: '', title: 'Perfil', end: true },
|
{ to: '', title: 'Perfil', end: true },
|
||||||
{ to: 'address', title: 'Endereço' },
|
{ to: 'address', title: 'Endereço' },
|
||||||
{ to: 'subscription', title: 'Plano' }
|
{ to: 'subscription', title: 'Plano' },
|
||||||
|
{ to: 'billing', title: 'Pagamentos' }
|
||||||
]
|
]
|
||||||
|
|
||||||
export function meta() {
|
export function meta() {
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ function Editing() {
|
|||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormLabel>Não listar no catálogo de cursos</FormLabel>
|
<FormLabel>Ocultar curso do catálogo público</FormLabel>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user