<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Martijn Smit</title>
    <description>The latest articles on DEV Community by Martijn Smit (@smitmartijn).</description>
    <link>https://dev.to/smitmartijn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F876641%2F6b293f65-dcf0-48b5-93d5-aa7e7d125eee.png</url>
      <title>DEV Community: Martijn Smit</title>
      <link>https://dev.to/smitmartijn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/smitmartijn"/>
    <language>en</language>
    <item>
      <title>Using Laravel Dusk to download Paddle payout PDFs</title>
      <dc:creator>Martijn Smit</dc:creator>
      <pubDate>Thu, 16 Jan 2025 10:06:20 +0000</pubDate>
      <link>https://dev.to/smitmartijn/using-laravel-dusk-to-download-paddle-payout-pdfs-2bim</link>
      <guid>https://dev.to/smitmartijn/using-laravel-dusk-to-download-paddle-payout-pdfs-2bim</guid>
      <description>&lt;p&gt;When you have multiple Paddle accounts for different products—monthly accounting tasks end up consuming more time than you’d like. For each payout, I’d log into all my accounts, download the payout PDFs split up between the US and RoW (rest of world) regions, and import them into my accounting software. After a few times, I decided to automate it using Laravel Dusk and I figured I’d share the solution here.&lt;/p&gt;

&lt;p&gt;This blog post introduces a new GitHub repository that uses Laravel Dusk to log into Paddle’s web interface, navigate to the payouts page, and download payout PDFs. If you find yourself manually retrieving Paddle payout data every month, this might just be the automation you need.&lt;/p&gt;

&lt;p&gt;Continue reading for the context and a walkthrough, or go directly to the repo: &lt;a href="https://github.com/smitmartijn/laravel-dusk-paddle-payouts-download" rel="noopener noreferrer"&gt;https://github.com/smitmartijn/laravel-dusk-paddle-payouts-download&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;If you’re using Paddle as a payment processor, you know that their payouts arrive monthly, and each payout comes with a PDF you’ll need for accounting. If you have multiple products with separate Paddle accounts, this can quickly become a time-consuming task. So, this post and project is for anyone using Paddle and has multiple accounts, or just want to make their life a bit easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;There’s a Laravel Dusk test script in the repository that handles everything from logging in to downloading the payout PDFs. Here’s a quick breakdown of the steps it follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetching Paddle accounts: Before running the script, make sure you have PaddleAccount records set up in your database. You can also strip out the PaddleAccount and PaddlePayout models if you’d like.&lt;/li&gt;
&lt;li&gt;Logging in and navigating: The script logs into the Paddle dashboard using the credentials provided and navigates to the Payouts page.&lt;/li&gt;
&lt;li&gt;Downloading the PDFs: It retrieves the available payout PDFs for both “US” and “RoW” (Rest of World) invoices and stores them in storage/app/private/paddle_invoices/.&lt;/li&gt;
&lt;li&gt;Extracting totals: Using the PdfToText package, it extracts the total payout amounts from the PDFs.&lt;/li&gt;
&lt;li&gt;Updating records: Finally, it creates or updates the PaddlePayout records in the database with the extracted data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;The GitHub repository contains an example Laravel project with the PaddleDownloadPayoutPdfTest.php file as how I am using it myself. You can strip that file for parts, or clone the entire project, create a database and run the migrations, create a PaddleAccount record, and then run php artisan dusk to test it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;This script solved a recurring annoyance for me by turning hours of manual work (even if it was just once a month) into a task that runs in minutes without my involvement. While I haven’t added the code where it takes the PaddlePayouts and syncs them to my accounting software, you can basically do anything with the PDFs, once they’re stored locally.&lt;/p&gt;

&lt;p&gt;If you want to check out the full code or give it a try, head over to the GitHub repository. Contributions and feedback are always welcome.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>paddle</category>
      <category>php</category>
    </item>
    <item>
      <title>New PHP Package: Discord Table Builder</title>
      <dc:creator>Martijn Smit</dc:creator>
      <pubDate>Fri, 13 Sep 2024 10:44:32 +0000</pubDate>
      <link>https://dev.to/smitmartijn/new-php-package-discord-table-builder-2chk</link>
      <guid>https://dev.to/smitmartijn/new-php-package-discord-table-builder-2chk</guid>
      <description>&lt;p&gt;Hey there! If you've ever tried to create a table in a Discord message, you know it's not exactly straightforward. The Discord API doesn't have built-in support for tables or any easy way to format tabular data. It's one of those small but annoying problems that can really slow you down.&lt;/p&gt;

&lt;p&gt;After searching for an existing solution and coming up empty, I decided to tackle this issue head-on. The result? A new PHP package called Discord Table Builder.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Discord Table Builder All About?
&lt;/h2&gt;

&lt;p&gt;Discord Table Builder is a PHP package designed to help you create tables for Discord messages without the hassle. Here's what it brings to the table (pun intended):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically figures out the width of each column based on the content&lt;/li&gt;
&lt;li&gt;Supports multiple rows and columns (within Discord API limits)&lt;/li&gt;
&lt;li&gt;Lets you add a URL to any row, making it clickable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of a table with a &lt;a href="https://whatpulse.org" rel="noopener noreferrer"&gt;WhatPulse&lt;/a&gt; leaderboard, the reason I created this package:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzzqmb1wlheuukvxj4n9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzzqmb1wlheuukvxj4n9.png" alt="Image description" width="547" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;First things first, let's get the package installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require smitmartijn/discord-table-builder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;Let's walk through a quick example. Say you're building a game leaderboard. Here's how you'd use Discord Table Builder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Smitmartijn\DiscordTableBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Set up the leaderboard table&lt;/span&gt;
&lt;span class="nv"&gt;$table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DiscordTableBuilder\DiscordEmbedTable&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="s1"&gt;'titles'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Position'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Player'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Points'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="s1"&gt;'padding'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Add some rows (with a special URL for first place)&lt;/span&gt;
&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addRow&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'1st'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Charlie'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'300'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'url'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'https://lostdomain.org'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addRow&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'2nd'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Alice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'100'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Prepare for Discord API call&lt;/span&gt;
&lt;span class="nv"&gt;$messageContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s2"&gt;"tts"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;"embeds"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"title"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Weekly Leaderboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"description"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Here are the top players this week:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"fields"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toField&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Send to Discord (you'll need your own function for this part)&lt;/span&gt;
&lt;span class="nf"&gt;sendToDiscord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$messageContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;When you send this message, your Discord users will see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1st             Charlie        300
2nd             Alice          100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's a cool feature - that first row is actually a clickable link to &lt;a href="https://lostdomain.org" rel="noopener noreferrer"&gt;https://lostdomain.org&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Discord Table Builder is there to make it easier when it comes to formatting data in Discord messages. No more fiddling with spaces or struggling with alignment - just plug in your data and you're good to go.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions, feel free to check out the project on &lt;a href="https://github.com/smitmartijn/discord-table-builder/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. And if you use it in your projects, I'd love to hear about it!&lt;/p&gt;

</description>
      <category>php</category>
      <category>discord</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
