wip import product functionality and page

This commit is contained in:
María
2025-08-21 13:40:01 +02:00
parent 4a05f8915b
commit f0fdc71fa7
6 changed files with 411 additions and 7 deletions

View File

@@ -184,8 +184,6 @@
<div class="submit-btn" align="center">
<SubmitButton text="guardar" image-url="" />
</div>
PRODUCT FORM: {{ productForm }} <br><br><br>
FORM: {{ form }}
</form>
</template>

View File

@@ -70,6 +70,7 @@ export default {
})
if (this.form.source !== 'MANUAL' && this.form.history) {
try {
//TODO: Review Fetching the sync date from the history endpoint
const result = await $fetch(`history/${this.form.history}/`, {
baseURL: config.public.baseURL,
method: 'GET',

View File

@@ -1,15 +1,408 @@
<template>
<div class="container">
<BModal
id="modal-center"
v-model="activeModal"
centered
title="latienda.coop"
:ok-variant="modalColor"> {{ modalText }}
</BModal>
<BContainer class="container">
<BRow align-h="start">
<div class="import-products">
<div
class="header"
@click="importOpen = !importOpen"
>
<h4 class="title">
Importar productos desde CSV &nbsp;
<img
src="@/assets/img/latienda-arrow-down.svg"
alt=""
class="arrow"
:class="{
'close': !importOpen,
'open': importOpen }"
/>
</h4>
</div>
<BCollapse id="collapse-import" v-model="importOpen">
<div class="description">
<p>
La función <strong>Importar CSV</strong> te permite subir tus
productos a Latienda.coop sin tener que hacerlo manualmente.
Puedes ponerles nombres a las columnas en tu hoja de cálculo con
las siguientes etiquetas para que los campos se asocien
automáticamente en tus productos:
</p>
<ol>
<li>
<strong>SKU: </strong>usa esta columna para proporcionar un
identificador único a tu producto.
</li>
<li>
<strong>Nombre de producto: </strong>asigna un nombre. Es el
texto que se ve primero al listar el producto.
</li>
<li>
<strong>Descripción: </strong>proporciona los detalles del
producto.
</li>
<li><strong>Imagen: </strong>url de la imagen del producto.</li>
<li>
<strong>URL: </strong>enlace a la página del producto si
existe.
</li>
<li>
<strong>Precio: </strong>precio en euros con IVA incluido. Si
se deja en blanco aparecerá el texto "Consultar precio".
</li>
<li>
<strong>Gastos de envío: </strong>importe adicional por los
gastos de envío. Si se deja en blanco, o nulo, aparecerá el
texto "Sin gastos de envío".
</li>
<li>
<strong>Condiciones de envío: </strong>aquí se puede indicar
las condiciones de envío específicas para cada producto. Si se
deja en blanco se mostrarán las opciones por defecto de tu
cooperativa.
</li>
<li>
<strong>Descuento: </strong>porcentaje de descuento sobre el
precio del producto.
</li>
<li><strong>Stock: </strong>número de unidades disponibles.</li>
<li>
<strong>Tags: </strong>etiquetas libres que describen al
producto. Usa el carácter "/" para separar cada tag.
</li>
<li>
<strong>Categoría: </strong>clasificación principal del
producto. el Latienda.coop usamos la taxonomía de Google.
Puedes ver todas las categorías disponibles
<a
href="https://www.google.com/basepages/producttype/taxonomy-with-ids.es-ES.txt"
target="_blank"
>aquí</a
>. Elige la categoría o subcategoría de cualquier nivel que
mejor defina a tu producto.
</li>
<li>
<strong>Identificadores: </strong>identificador único
opcional.
</li>
</ol>
<br />
<p>
Descarga la
<a href="/plantilla-latienda.csv" download="plantilla.csv" type="text/csv">plantilla</a>
de referencia.
</p>
<form @submit.prevent="submitFile">
<div>
<h1>Importar producto /editar/productos/importar</h1>
<label for="file"
>Archivo .csv
<input
id="file"
type="file"
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
placeholder="Elige un archivo"
required
@change="handleFile"
/>
</label>
</div>
<SubmitButton text="Importar" image-url="" />
</form>
</div>
</BCollapse>
</div>
</BRow>
</BContainer>
<BContainer class="container">
<BRow align-h="start">
<div class="import-products">
<div
class="header"
@click="syncOpen = !syncOpen"
>
<h4 class="title">
Sincronización con tu tienda online &nbsp;
<img
src="@/assets/img/latienda-arrow-down.svg"
alt=""
class="arrow"
:class="{ 'close': !syncOpen, 'open': syncOpen }"
/>
</h4>
</div>
<BCollapse id="collapse-sync" v-model="syncOpen">
<div v-if="platform" class="description">
<div class="platform">
<BFormInput v-model="platform" type="text" disabled />
</div>
<br />
<div class="credentials">
<BFormTextarea
v-model="credentials"
type="text"
rows="4"
disabled
/>
</div>
<br />
<p>
Si los datos no son correctos puedes editarlos en tu
<NuxtLink to="/editar/cooperativa">cooperativa</NuxtLink>
</p>
</div>
<div v-else class="description">
<p>
No tienes configurada tu tienda online. <br /><br />
<NuxtLink to="/editar/cooperativa">Edita</NuxtLink> la
información de tu cooperativa y añade la información necesaría
para la sincronización con Woocommerce
</p>
</div>
<form @submit.prevent="syncWebsite">
<SubmitButton
text="Lanzar sincronización"
image-url=""
/>
</form>
</BCollapse>
</div>
</BRow>
</BContainer>
</div>
</template>
<script>
export default {
import { useAuthStore } from '@/stores/auth'
export default {
setup() {
definePageMeta({
layout: 'editar',
middleware: 'auth',
auth: { authority: 'COOP_MANAGER' },
})
const auth = useAuthStore();
return {
auth
}
},
data() {
return {
file: null,
importOpen: false,
syncOpen: false,
platform: null,
credentials: null,
syncForm: null,
activeModal: false,
modalText: '',
modalColor: '',
}
},
async mounted() {
try{
const config = useRuntimeConfig()
const data = await $fetch('my_company/', {
baseURL: config.public.baseURL,
method: 'GET',
headers: {
Authorization: `Bearer ${this.auth.access}`
}
})
if (data.company.platform === 'WOO_COMMERCE')
this.platform = 'Woocommerce'
this.credentials = JSON.stringify(data.company.credentials, undefined, 2)
this.syncForm = {
key: data.company.credentials['key'],
secret: data.company.credentials['secret'],
url: data.company.shop_link
}
// const historyResults = await $fetch(`/history/`, {
// baseURL: config.public.baseURL,
// method: 'GET',
// headers: {
// Authorization: `Bearer ${this.auth.access}`
// }
// })
// console.log(historyResults.data)
} catch (error) {
console.error(error)
}
},
methods: {
async handleFile(e) {
const selectedFile = await e.target.files[0]
this.file = selectedFile
},
async submitFile() {
const config = useRuntimeConfig()
//TODO: Review functionality
try {
const formData = new FormData()
formData.append('csv_file', this.file)
console.log('Form data to submit:', formData)
await $fetch('/load_products/',{
baseURL: config.public.baseURL,
method: 'POST',
body: this.file,
headers: {
Authorization: `Bearer ${this.auth.access}`,
},
})
this.modalText = 'Productos importados correctamente'
this.modalColor = 'success'
this.activeModal = true
} catch {
this.modalText = 'Ha habido un error'
this.modalColor = 'danger'
this.activeModal = true
}
// Clear the file input
this.file = null
},
async syncWebsite() {
const config = useRuntimeConfig()
//TODO: Error 500, its seems to be backend issue
try {
console.log('Sync form data:', this.syncForm)
await $fetch('/sync_shop/',{
baseURL: config.public.baseURL,
method: 'POST',
body: {
url: this.syncForm.url,
key: this.syncForm.key,
secret: this.syncForm.secret
},
headers: {
Authorization: `Bearer ${this.auth.access}`,
},
})
this.modalText = 'Sincronización iniciada'
this.modalColor = 'success'
this.activeModal = true
} catch {
this.modalText = 'Ha habido un error'
this.modalColor = 'danger'
this.activeModal = true
}
},
},
}
</script>
<style lang="scss" scoped>
.container {
margin-top: 40px;
margin-bottom: 80px;
}
.header {
width: 100%;
outline: none;
}
.title {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.arrow {
width: 20px;
height: 20px;
}
.description {
margin-top: 30px;
}
.close {
transform: rotate(-90deg);
opacity: 1;
transition: all 0.5s;
}
.open {
transition: all 0.5s;
}
.import-products {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
}
.title {
color: $color-navy;
@include mobile {
margin-top: 70px;
}
}
.subtitle {
color: $color-navy;
font-size: $l;
}
ol {
list-style-type: none;
counter-reset: a;
}
ol > li {
counter-increment: a;
position: relative;
list-style: none;
margin-top: 18px;
margin-left: 35px;
}
ol > li:before {
color: #fff;
background: $color-navy;
width: 18px;
height: 18px;
top: 2px;
left: -35px;
position: absolute;
line-height: 20px;
font-size: 12px;
content: counter(a);
text-align: center;
font-weight: 400;
-webkit-text-stroke: 0.04em;
}
.error {
color: $color-error;
}
label {
text-align: left;
color: $color-navy;
font-weight: $bold;
font-size: $xs;
}
.cont-col {
margin: 15px 0;
display: flex;
flex-direction: column;
@include mobile {
margin: 15px 80px;
}
}
.input {
font-size: $s;
}
</style>

11
public/README.md Normal file
View File

@@ -0,0 +1,11 @@
# STATIC
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your static files.
Each file inside this directory is mapped to `/`.
Thus you'd want to delete this README.md before deploying to production.
Example: `/static/robots.txt` is mapped as `/robots.txt`.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1 @@
sku,nombre-producto,descripcion,imagen,url,precio,gastos-envio,cond-envio,descuento,stock,tags,categoria,identificadores
1 sku nombre-producto descripcion imagen url precio gastos-envio cond-envio descuento stock tags categoria identificadores